Получение текущей страницы

98

В моем представлении прокрутки я хочу получить текущую отображаемую страницу (возможно, страница - неправильный термин). Я не могу найти ни одной переменной, содержащей это. Но я думаю, что его нужно где-то держать, так как индикатор может показать, какой подвид прокрутки отображается в данный момент.

Это полностью скрыто от нас, или я могу получить к нему доступ?

TheNeil
источник

Ответы:

263

Для UIScrollViewтекущей страницы нет свойства. Вы можете рассчитать это с помощью:

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

Если вы хотите округлить до ближайшей страницы вверх или вниз, используйте:

CGFloat width = scrollView.frame.size.width;
NSInteger page = (scrollView.contentOffset.x + (0.5f * width)) / width;
AlexVogel
источник
7
Не забывайте использовать UIScrollViewDelegateдля получения текущей страницы при прокрутке пользователя!
Сэм Спенсер
Это может вызвать проблемы при вращении.
Джейсон МакКрири
пожалуйста, добавьте быструю версию
fnc12
1
Это не всегда работает, иногда ширина рамки неправильная.
Родриго Руис
Так получается не всегда. Иногда я получаю страницу как 0, что в моем случае неверно.
Sneha
32

Я очень рекомендую вам использовать этот код

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

но если вы используете этот код, ваше представление не обязательно должно быть точно на странице, которую выдает indexOfPage. Это потому, что я также рекомендую вам использовать этот код только в этом методе

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

который вызывается, когда ваш scrollView заканчивает прокрутку и чтобы номер вашей страницы был действительно четким

Я рекомендую вам установить для вашего scrollView режим paged с помощью этого кода

[scrollView setPagingEnabled:YES];

Итак, наконец, это должно выглядеть так

-(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
}
Иржи Захалка
источник
не работает на устройстве iOS7 (скомпилировано с XCODE 6.2) contentOffset.x равно 639 вместо 640 (не спрашивайте меня, почему ...) при scrollViewDidEndDecelerating. user363349 ответ правильный: вернуть этаж ((self.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
Василий
Так получается не всегда. Иногда я получаю страницу как 0, что в моем случае неверно.
Sneha
30

Я бы быстро сделал это в расширении:

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

Тогда просто позвоните:

scrollView.currentPage
Андрюс Степонавичюс
источник
10
Почти идеально, мне пришлось удалить +1 в конце, так как в моем мире все равно нулю
mvandillen
12

То же, что и выше, но как категория


@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
источник
6
Это перестаралось, просто используйте return round (self.contentOffset.x / self.frame.size.width); Гораздо проще и понятнее ..
Леонард Паули
-1 @LeonardPauli. Вышеупомянутая реализация возвращает страницу, которая видна более чем на 50%. Наивная реализация изменяет значение страницы только тогда, когда подпредставление scrollview занимает все границы scrollview.
пользователь
1
@user Во-первых, floor () округляет всегда вниз, а round () округляет вверх, если десятичная часть> = 5, иначе вниз. При этом, пол (а) = круглый (а-0,5). Давайте займемся простой алгеброй. этаж ((ab / 2) / b) +1 = пол (a / b-0,5) +1 = круглый (a / b-0,5-0,5) +1 = круглый (a / b-1) +1 = круглый ( а / б). Смотри! Вроде пол ((ab / 2) / b) +1 = круглый (a / b)! Математический.
Леонард Паули
Но да, если бы я по какой-то причине использовал пол, то вы были бы совершенно правы! ;)
Леонард Паули
9

Другой способ :

extension MyViewController: UIScrollViewDelegate {
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let width = scrollView.frame.width
        let page = Int(round(scrollView.contentOffset.x/width))
        print("CurrentPage:\(page)")
    }
}
Хеманг
источник
6

Просто разделите текущее смещение на размер страницы:

CGFloat pageNum = (int)(scrollView.contentOffset.x / scrollView.frame.size.width);
aoakenfo
источник
11
Приведение к int, а затем присвоение float? Почему бы не сделать pageNum также int;)
Клаас
6

Здесь уже есть несколько хороших ответов. Однако для сценариев, когда контент не помещается точно на страницу - и если вы, как и я, хотите использовать результат для a UIPageControl, то важно использоватьceil функцию.

Возьмем пример, когда у меня есть «четыре с небольшим» страницы контента.

Я буду основывать это на моем текущем примере из реальной жизни. Ширина размера контента 3140 точек. Исходя из размера рамки представления моей коллекции, ширина страницы составляет 728.

Итак, количество страниц равно:

 3140 / 728 = 4.313 

Моему numberOfPagesбудет пять. Четыре из них будут отображаться полностью, а последняя из них - пятая страница - покажет оставшийся 0.313контент.

Теперь numberOfPagesпять означает, что индексы страниц будут 0, 1, 2, 3 и 4.

Когда я смахиваю вправо, перемещаясь к окончательному смещению, scrollViewDidEndDeceleratingметод дает окончательное смещение по оси X, равное 2412.

Применяя расчет округления:

2412 / 728 = 3.313 then rounded = 3

Это неверно. Страница, которую просматривает пользователь по смещению, должна быть:

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

Правильный расчет с использованием 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
}
Макс Маклауд
источник
4

Решение Aoakenfo потрясающее, это еще одно решение, объединяющее ваш код с функцией scrollViewDidScroll и 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;
    }
}
пабловерд
источник
1
Это жадно, а не лениво ... Это тоже не MVC. Гораздо более простой способ - сделать currentPage недействительным при прокрутке и установить его только по запросу ... все из подкласса или категории в UIScrollView
4

Для быстрого я бы просто использовал это

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

Довольно просто, он в основном берет позицию scrollview x, делит ее на ширину scrollview, а затем округляет.

нептуны
источник
3

В xCode 7.x swift 2.x вы можете:

//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
    }
}
Алессандро Орнано
источник
2

Я извлек это из нескольких наших приложений ...

- (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;
}

Полный исходный код здесь


источник
1

Вы используете UIPageControl? Если так, то у этого есть currentPageсвойство. Если нет, я думаю, вам нужно рассчитать индекс страницы из смещения scrollView.

Rengers
источник
0

Если кто-то ищет способ сделать на C # для 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);
    }

Этот геттер и сеттер должны предоставить вам текущую страницу, а также позволить вам прокрутить до указанной страницы.

Soan Saini
источник
0

Расширение Swift 5.1+ UIScrollView (без ключевого слова return)

extension UIScrollView {

    var currentPage: Int {
        Int(round(self.contentOffset.x / self.frame.width))
    }
}
Диего Каррера
источник