web-dev-qa-db-fra.com

iOS6 UICollectionView et UIPageControl - Comment obtenir une cellule visible?

En étudiant les nouvelles fonctionnalités d'iOS6, j'ai eu une question sur ICollectionView .
Je le teste actuellement avec la disposition Flow et la direction de défilement définie sur horizontal, le défilement et la pagination étant activés. J'ai défini sa taille exactement comme les cellules de ma coutume, afin qu'elle puisse s'afficher une à la fois, et en la faisant défiler latéralement, l'utilisateur verrait les autres cellules existantes.

Cela fonctionne parfaitement.

Maintenant, je veux ajouter et IPageControl à la vue de collection que j'ai créée, afin qu'elle puisse montrer quelle cellule est visible et combien de cellules s'y trouvent.

La création du contrôle de page était plutôt simple, le cadre et numberOfPages définis.

Le problème que je rencontre, comme les points d'interrogation, est de savoir comment obtenir la cellule actuellement visible dans la vue de la collection, afin qu'elle puisse changer la page courante du contrôle de page.

J'ai essayé des méthodes déléguées, comme cellForItemAtIndexPath, mais il est fait pour charger des cellules, pas pour les afficher. didEndDisplayingCell se déclenche lorsqu'une cellule n'est plus affichée, l'événement inverse de ce dont j'ai besoin.

Il semble que -visibleCells et -indexPathsForVisibleItems, les méthodes d'affichage de collection, soient le bon choix pour moi, mais j'ai rencontré un autre problème. Quand les déclencher?

Merci d'avance, j'espère que je me suis fait assez clair pour que vous puissiez me comprendre!

36
gazzola

Vous devez vous configurer en tant que UIScrollViewDelegate et implémenter le scrollViewDidEndDecelerating:méthode comme ceci:

Objectif-C

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    CGFloat pageWidth = self.collectionView.frame.size.width;
    self.pageControl.currentPage = self.collectionView.contentOffset.x / pageWidth;
}

rapide

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {

    let pageWidth = self.collectionView.frame.size.width
    pageControl.currentPage = Int(self.collectionView.contentOffset.x / pageWidth)
}
91
Sendoa

J'ai également eu du mal avec cela pendant un certain temps, puis on m'a conseillé de vérifier les classes parentes d'UICollectionView. L'un d'eux se trouve être IScrollView et si vous vous configurez comme IScrollViewDelegate , vous avez accès à des méthodes très utiles telles que scrollViewDidEndDecelerating , un excellent endroit pour mettre à jour UIPageControl.

18
Not Randy Marsh

Je recommanderais un petit calcul et une manipulation optimisés car cela mettra à jour le contrôle de la page immédiatement dans n'importe quelle position de défilement avec une meilleure précision.

La solution ci-dessous fonctionne avec n'importe quelle vue de défilement ou sous-classe (UITableView UICollectionView et autres)

dans la méthode viewDidLoad, écrivez ceci

scrollView.delegate = self

puis utilisez le code de votre langue:

Swift 3

func scrollViewDidScroll(_ scrollView: UIScrollView) 
    {
       let pageWidth = scrollView.frame.width
       pageControl.currentPage = Int((scrollView.contentOffset.x + pageWidth / 2) / pageWidth)
    }

Swift 2:

func scrollViewDidScroll(scrollView: UIScrollView) 
{
   let pageWidth = CGRectGetWidth(scrollView.frame)
   pageControl.currentPage = Int((scrollView.contentOffset.x + pageWidth / 2) / pageWidth)
}

Objectif c

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    CGFloat pageWidth = self.collectionView.frame.size.width;
    self.pageControl.currentPage = (self.collectionView.contentOffset.x + pageWidth / 2) / pageWidth;
}
17

Une autre option avec moins de code consiste à utiliser le chemin d'index des éléments visibles et à définir le contrôle de page.

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    self.pageControl.currentPage = [[[self.collectionView indexPathsForVisibleItems] firstObject] row];
}
8
Ramesh
  1. Placez PageControl dans votre vue ou défini par Code.
  2. Définir IScrollViewDelegate
  3. Dans Collectionview -> cellForItemAtIndexPath (Method) ajoutez le code ci-dessous pour calculer le nombre de pages,

int pages = étage (ImageCollectionView.contentSize.width/ImageCollectionView.frame.size.width); [pageControl setNumberOfPages: pages];

Ajoutez la méthode ScrollView Delegate,

marque pragma - UIScrollVewDelegate pour UIPageControl

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
    CGFloat pageWidth = ImageCollectionView.frame.size.width;
    float currentPage = ImageCollectionView.contentOffset.x / pageWidth;

    if (0.0f != fmodf(currentPage, 1.0f))
    {
        pageControl.currentPage = currentPage + 1;
    }
    else
    {
        pageControl.currentPage = currentPage;
    }
    NSLog(@"finishPage: %ld", (long)pageControl.currentPage);
}
5
Ramdhas

Je sais que c'est une ancienne mais j'ai juste besoin d'implémenter à nouveau ce type de fonctionnalité et d'avoir un peu à ajouter qui donne une réponse plus complète.

Premièrement: L'utilisation de scrollViewDidEndDecelerating suppose que l'utilisateur a levé son doigt tout en faisant glisser (plus comme une action de film) et qu'il y a donc une phase de décélération. Si l'utilisateur traîne sans lever le doigt, le UIPageControl indiquera toujours l'ancienne page d'avant le début du glissement. Au lieu de cela, l'utilisation du rappel scrollViewDidScroll signifie que la vue est mise à jour à la fois après le glisser-déplacer et également pendant le glisser-déplacer, ce qui la rend beaucoup plus réactive et précise pour l'utilisateur.

Deuxièmement: En se basant sur pagewidth pour calculer l'index sélectionné, toutes les cellules ont la même largeur et il y a une cellule par écran. tirer parti de la méthode indexPathForItemAtPoint sur UICollectionView donne un résultat plus résilient qui fonctionnera pour différentes dispositions et tailles de cellule. L'implémentation ci-dessous suppose que le centre du cadre est la cellule souhaitée à représenter dans le pagecontrol. De plus, s'il y a des espacements intercellulaires, il y aura des moments pendant le défilement lorsque le selectedIndex pourrait être nul ou facultatif, donc cela doit être vérifié et déballé avant de définir sur la pageControl.

 func scrollViewDidScroll(scrollView: UIScrollView) {
   let contentOffset = scrollView.contentOffset
   let centrePoint =  CGPointMake(
    contentOffset.x + CGRectGetMidX(scrollView.frame),
    contentOffset.y + CGRectGetMidY(scrollView.frame)
   )
   if let index = self.collectionView.indexPathForItemAtPoint(centrePoint){
     self.pageControl.currentPage = index.row
   }
 }

Encore une chose - définissez le nombre de pages sur le UIPageControl avec quelque chose comme ceci:

  func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    self.pageControl.numberOfPages = 20
    return self.pageControl.numberOfPages
  } 
4
Dallas Johnson

Simple Swift

public func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
    pageControl.currentPage = (collectionView.indexPathsForVisibleItems().first?.row)!
}

UIScrollViewDelegate est déjà implémenté si vous implémentez UICollectionViewDelegate

3
Michael