Pobieranie bieżącej strony

97

W moim widoku przewijania chcę uzyskać bieżącą wyświetlaną stronę (może strona nie jest właściwym terminem). Nie mogę znaleźć żadnej zmiennej, która to przechowuje. Ale myślę, że trzeba to gdzieś trzymać, ponieważ wskaźnik jest w stanie pokazać, który podwidok widoku przewijania jest obecnie wyświetlany.

Czy jest to całkowicie przed nami ukryte, czy jest dla mnie sposób, aby uzyskać do niego dostęp?

TheNeil
źródło

Odpowiedzi:

263

Nie ma UIScrollViewwłaściwości dla bieżącej strony. Możesz to obliczyć za pomocą:

int page = scrollView.contentOffset.x / scrollView.frame.size.width;

Jeśli chcesz zaokrąglić w górę lub w dół do najbliższej strony, użyj:

CGFloat width = scrollView.frame.size.width;
NSInteger page = (scrollView.contentOffset.x + (0.5f * width)) / width;
AlexVogel
źródło
7
Nie zapomnij użyć, UIScrollViewDelegateaby uzyskać bieżącą stronę, gdy użytkownik przewija!
Sam Spencer
Może to powodować problemy w przypadku rotacji.
Jason McCreary
proszę dodać szybką wersję
fnc12
1
To nie zawsze działa, czasami szerokość ramy jest nieprawidłowa.
Rodrigo Ruiz
To nie zawsze działa. Czasami otrzymuję stronę jako 0, co jest błędne w moim przypadku.
Sneha
32

Całkiem polecam użycie tego kodu

int indexOfPage = scrollView.contentOffset.x / scrollView.frame.size.width;

ale jeśli użyjesz tego kodu, twój widok nie musi znajdować się dokładnie na stronie, którą daje indexOfPage. To dlatego, że również polecam używać tego kodu tylko w tej metodzie

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{}

która jest wywoływana, gdy scrollView kończy przewijanie i ma naprawdę ostry numer strony

Zalecam ustawienie scrollView na stronicowane włączone za pomocą tego kodu

[scrollView setPagingEnabled:YES];

Więc w końcu powinno tak wyglądać

-(void) methodWhereYouSetYourScrollView
{
   //set scrollView
   [scrollView setPagingEnabled:YES];
   scrollView.delegate = self;
}

-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
   int indexOfPage = scrollView.contentOffset.x / scrollView.frame.size.width;
   //your stuff with index
}
Jiří Zahálka
źródło
nie działa na urządzeniu iOS7 (skompilowanym z XCODE 6.2) contentOffset.x równa się 639 zamiast 640 (nie pytaj mnie dlaczego ...) podczas scrollViewDidEndDecelerating. user363349 odpowiedź jest prawidłowa: return floor ((self.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
Wasilij
To nie zawsze działa. Czasami otrzymuję stronę jako 0, co jest błędne w moim przypadku.
Sneha
30

Szybko zrobiłbym to w rozszerzeniu:

extension UIScrollView {
    var currentPage:Int{
        return Int((self.contentOffset.x+(0.5*self.frame.size.width))/self.frame.width)+1
    }
}

Następnie zadzwoń:

scrollView.currentPage
Andrius Steponavičius
źródło
10
Prawie idealnie, musiałem usunąć +1 na końcu, ponieważ w moim świecie wszystko jest zerowe
mvandillen
12

Jak wyżej, ale jako kategoria


@interface UIScrollView (CurrentPage)
-(int) currentPage;
@end
@implementation UIScrollView (CurrentPage)
-(int) currentPage{
    CGFloat pageWidth = self.frame.size.width;
    return floor((self.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
}
@end
user363349
źródło
6
To przesadzone, po prostu użyj return round (self.contentOffset.x / self.frame.size.width); Dużo prostsze i łatwiejsze do zrozumienia ..
Leonard Pauli
-1 @LeonardPauli. Powyższa implementacja zwraca stronę, która jest widoczna w ponad 50%. Naiwna implementacja zmienia wartość strony tylko wtedy, gdy widok podrzędny widoku przewijania zajmuje całe granice widoku przewijania.
użytkownik
1
@user Po pierwsze, floor () zaokrągla zawsze w dół, a round () zaokrągla w górę, jeśli część dziesiętna wynosi> = 5, w przeciwnym razie w dół. Mając to na uwadze, floor (a) = round (a-0.5). Zróbmy prostą algebrę. podłoga ((ab / 2) / b) +1 = podłoga (a / b-0,5) +1 = okrągła (a / b-0,5-0,5) +1 = okrągła (a / b-1) +1 = okrągła ( a / b). Popatrz! Wygląda na to, że podłoga ((ab / 2) / b) +1 = okrągły (a / b)! Matemagiczne.
Leonard Pauli
Ale tak, gdybym z jakiegoś powodu użył zamiast tego podłogi, miałbyś całkowitą rację! ;)
Leonard Pauli
8

Inny sposób :

extension MyViewController: UIScrollViewDelegate {
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let width = scrollView.frame.width
        let page = Int(round(scrollView.contentOffset.x/width))
        print("CurrentPage:\(page)")
    }
}
Hemang
źródło
6

Po prostu podziel bieżące przesunięcie przez rozmiar strony:

CGFloat pageNum = (int)(scrollView.contentOffset.x / scrollView.frame.size.width);
aoakenfo
źródło
11
Rzutowanie na int, a następnie przypisanie do pływaka? Dlaczego nie zrobić również pageNum int;)
Klaas
6

Jest tu już kilka dobrych odpowiedzi. Jednak w scenariuszach, w których treść nie pasuje dokładnie do strony - i jeśli tak jak ja chcesz użyć wyniku dla a UIPageControl, to konieczne jest użycie ceilfunkcji.

Weźmy przykład, w którym mam „cztery i trochę” strony treści.

Oprę to na moim obecnym przykładzie z życia. Szerokość rozmiaru treści to 3140 punktów. Na podstawie rozmiaru ramki widoku mojej kolekcji szerokość strony to 728.

Tak więc liczba stron jest równa:

 3140 / 728 = 4.313 

Mój numberOfPagesbędzie miał pięć lat. Cztery z nich wyświetlą się w całości, a ostatnia - strona piąta - pokaże pozostałą 0.313treść.

Teraz, numberOfPagesgdy jest pięć, oznacza, że ​​indeksy stron będą wynosić 0, 1, 2, 3 i 4.

Kiedy przesuwam palcem w prawo, przewijając w kierunku końcowego przesunięcia, scrollViewDidEndDeceleratingmetoda daje końcowe przesunięcie X o wartości 2412.

Stosowanie obliczenia zaokrąglenia:

2412 / 728 = 3.313 then rounded = 3

To jest niepoprawne. Strona przeglądana przez użytkownika według przesunięcia powinna być:

Offset / Page User Is Viewing
0        0
728      1
1456     2
2184     3
2412     4

Prawidłowe obliczenia przy użyciu ceil:

private func pageForOffset(offset:CGFloat, pageWidth width:CGFloat) -> Int
{
    let page = Int(ceil(offset / width))
    NSLog("\(__FUNCTION__) offset \(offset) width \(width) page \(page) ")
    return page
}
Max MacLeod
źródło
4

Szybko użyłbym tego

    let width = scrollView.frame.width
    let page = round(scrollView.contentOffset.x/width)

Całkiem proste, w zasadzie przyjmuje pozycję scrollview x, dzieli ją przez szerokość scrollview, a następnie zaokrągla.

neptunes
źródło
3

W xCode 7.x swift 2.x możesz:

//MARK: - ScrollView Extensions
// Get the current page number
extension UIScrollView {
    var currentPage: Int {
        return Int(round(self.contentOffset.x / self.bounds.size.width))
    }

// If you have reversed offset (start from contentSize.width to 0)
    var reverseCurrentPage: Int {
        return Int(round((contentSize.width - self.contentOffset.x) / self.bounds.size.width))-1
    }
}
Alessandro Ornano
źródło
3

Rozwiązanie Aoakenfo jest niesamowite, to kolejne rozwiązanie łączące Twój kod z funkcją scrollViewDidScroll i PageController

- (void)scrollViewDidScroll:(UIScrollView *)sender {
    if (sender == self.scroll) {
        int pageNum = (int)(self.scrPage.contentOffset.x / self.scrPage.frame.size.width);
        self.pagecontroller.currentPage =pageNum;
    }
}
pabloverd
źródło
1
To jest chciwe, nie leniwe ... To też nie jest MVC. O wiele prostszym sposobem jest unieważnienie bieżącej strony podczas przewijania i ustawianie jej tylko wtedy, gdy jest żądana ... wszystko z podklasy lub kategorii w UIScrollView
2

Wyodrębniłem to z kilku naszych aplikacji ...

- (NSInteger)currentPage
{
    if (0 == self.frame.size.width) {
        NSLog(@"frame width == 0!");
        return 0;
    }
    if (! self.currentPageValid) {
        _currentPage = round(self.contentOffset.x / self.frame.size.width);
        self.currentPageValid = YES;
    }
    return _currentPage;
}

Pełne źródło tutaj


źródło
1

Czy używasz UIPageControl? Jeśli tak, to ma currentPagewłaściwość. Jeśli nie, myślę, że będziesz musiał obliczyć indeks strony na podstawie przesunięcia scrollView.

Rengers
źródło
0

Jeśli ktoś szuka sposobu działania w języku C # dla platformy Xamarin

    public int CurrentIndex
    {
        get => (int)Math.Round(this.scrollView.ContentOffset.X / this.scrollView.Frame.Width);
        set => this.scrollView.ScrollRectToVisible(new CGRect(new CGPoint(this.scrollView.Frame.Size.Width * value, 0), this.scrollView.Frame.Size), true);
    }

Ten program pobierający i ustawiający powinien również zapewnić bieżącą stronę, umożliwiającą przewijanie do określonej strony

soan saini
źródło
0

Rozszerzenie Swift 5.1+ UIScrollView (pomijanie słowa kluczowego return)

extension UIScrollView {

    var currentPage: Int {
        Int(round(self.contentOffset.x / self.frame.width))
    }
}
Diego Carrera
źródło