Obtenir la page actuelle

97

Dans ma vue de défilement, je veux obtenir la page actuelle qui est affichée (peut-être que la page n'est pas le terme correct). Je ne trouve aucune variable qui contienne cela. Mais je pense qu'il doit être tenu quelque part, car l'indicateur est capable de montrer quelle sous-vue de la vue de défilement est actuellement affichée.

Cela nous est-il complètement caché ou y a-t-il un moyen pour moi d'y accéder?

TheNeil
la source

Réponses:

263

Il n'y a pas de UIScrollViewpropriété pour la page actuelle. Vous pouvez le calculer avec:

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

Si vous souhaitez arrondir vers le haut ou vers le bas à la page la plus proche, utilisez:

CGFloat width = scrollView.frame.size.width;
NSInteger page = (scrollView.contentOffset.x + (0.5f * width)) / width;
AlexVogel
la source
7
N'oubliez pas d'utiliser UIScrollViewDelegatepour obtenir la page actuelle lorsque l'utilisateur fait défiler!
Sam Spencer
Cela peut poser des problèmes lors de la rotation.
Jason McCreary
s'il vous plaît ajouter la version rapide
fnc12
1
Cela ne fonctionne pas toujours, parfois la largeur du cadre est incorrecte.
Rodrigo Ruiz
Cela ne fonctionne pas toujours. Parfois, j'obtiens la page 0, ce qui est faux dans mon cas.
Sneha
32

Je vous recommande plutôt d'utiliser ce code

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

mais si vous utilisez ce code, votre vue n'a pas besoin d'être exactement sur la page que indexOfPage vous donne. C'est parce que je vous recommande également d'utiliser ce code uniquement dans cette méthode

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

qui est appelé lorsque votre scrollView finit de défiler et d'avoir le numéro de votre page vraiment net

Je vous recommande de définir votre scrollView sur paginé activé avec ce code

[scrollView setPagingEnabled:YES];

Donc finalement ça devrait ressembler à ça

-(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
la source
ne fonctionne pas sur un appareil iOS7 (compilé avec XCODE 6.2) contentOffset.x vaut 639 au lieu de 640 (ne me demandez pas pourquoi ...) lors de scrollViewDidEndDecelerating. La réponse de l'utilisateur363349 est correcte: return floor ((self.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
Vassily
Cela ne fonctionne pas toujours. Parfois, j'obtiens la page 0, ce qui est faux dans mon cas.
Sneha
30

En rapide je le ferais en extension:

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

Alors appelez simplement:

scrollView.currentPage
Andrius Steponavičius
la source
10
Presque parfait, j'ai dû supprimer le +1 à la fin car tout est basé sur zéro dans mon monde
mvandillen
12

Comme ci-dessus mais en tant que catégorie


@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
la source
6
C'est exagéré, utilisez simplement return round (self.contentOffset.x / self.frame.size.width); Beaucoup plus simple et plus facile à comprendre ..
Leonard Pauli
-1 @LeonardPauli. L'implémentation ci-dessus renvoie la page qui est visible à plus de 50%. L'implémentation naïve ne change la valeur de la page que lorsque la sous-vue de la vue de défilement occupe toutes les limites de la vue de défilement.
utilisateur
1
@user Premièrement, floor () arrondit toujours vers le bas, et round () arrondit vers le haut si la partie décimale est> = 5, sinon vers le bas. Cela étant dit, plancher (a) = rond (a-0,5). Faisons une simple algèbre. plancher ((ab / 2) / b) +1 = plancher (a / b-0,5) +1 = rond (a / b-0,5-0,5) +1 = rond (a / b-1) +1 = rond ( un B). Regardez! Il semble que le sol ((ab / 2) / b) +1 = rond (a / b)! Mathemagical.
Leonard Pauli
Mais oui, si, pour une raison quelconque, j'avais utilisé le sol à la place, vous auriez eu parfaitement raison! ;)
Leonard Pauli
8

Une autre façon :

extension MyViewController: UIScrollViewDelegate {
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let width = scrollView.frame.width
        let page = Int(round(scrollView.contentOffset.x/width))
        print("CurrentPage:\(page)")
    }
}
Hemang
la source
6

Divisez simplement le décalage actuel par la taille de la page:

CGFloat pageNum = (int)(scrollView.contentOffset.x / scrollView.frame.size.width);
aoakenfo
la source
11
Casting en int puis attribution à un float? Pourquoi ne pas faire de pageNum int ainsi;)
Klaas
6

Il y a déjà de bonnes réponses ici. Cependant, pour les scénarios où le contenu ne rentre pas exactement dans une page - et si comme moi vous voulez utiliser le résultat pour a UIPageControl, alors il est essentiel d'utiliser la ceilfonction.

Prenons un exemple où j'ai "quatre et un peu" pages de contenu.

Je vais baser cela sur mon exemple actuel de la vie réelle. La largeur de la taille du contenu est de 3140 points. En fonction de la taille du cadre de vue de ma collection, la largeur de la page est de 728.

Donc, le nombre de pages est égal à:

 3140 / 728 = 4.313 

Mon numberOfPagesva avoir cinq ans. Quatre d'entre eux seront affichés dans leur intégralité, et le dernier - la page cinq - montrera le reste 0.313du contenu.

Maintenant, numberOfPagesêtre cinq signifie que les index de page seront 0, 1, 2, 3 et 4.

Lorsque je glisse vers la droite, en recherchant le décalage final, la scrollViewDidEndDeceleratingméthode donne un décalage X final de 2412.

Application du calcul d'arrondi:

2412 / 728 = 3.313 then rounded = 3

C'est incorrect. La page que l'utilisateur consulte par décalage doit être:

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

Le calcul correct en utilisant 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
la source
4

Pour rapide, je voudrais juste utiliser ça

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

Assez simple, il prend essentiellement la position scrollview x, la divise par la largeur de scrollview, puis l'arrondit.

neptunes
la source
3

Dans xCode 7.x swift 2.x, vous pouvez faire:

//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
la source
3

La solution d'Aoakenfo est incroyable, c'est une autre solution combinant votre code avec la fonction scrollViewDidScroll et 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
la source
1
C'est gourmand, pas paresseux ... Ce n'est pas non plus MVC. Un moyen beaucoup plus simple consiste à invalider la page actuelle lors du défilement et à ne la définir que lorsqu'elle est demandée ... le tout à partir d'une sous-classe ou d'une catégorie sur UIScrollView
2

J'ai extrait ceci de quelques-unes de nos applications ...

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

Source complète ici


la source
1

Utilisez-vous un UIPageControl? Si tel est le cas, cela a une currentPagepropriété. Sinon, je pense que vous devrez calculer l'index de la page à partir du décalage scrollView.

Rengers
la source
0

Si quelqu'un cherche un moyen de faire en C # pour 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);
    }

Ce getter et Setter devraient vous fournir la page actuelle et vous permettre de faire défiler jusqu'à la page spécifiée

soan saini
la source
0

Extension Swift 5.1+ UIScrollView (en omettant le mot-clé de retour)

extension UIScrollView {

    var currentPage: Int {
        Int(round(self.contentOffset.x / self.frame.width))
    }
}
Diego Carrera
la source