objective-c ios ios6

objective c - iOS6 UICollectionView y UIPageControl: ¿cómo obtener una celda visible?



objective-c (7)

Mientras estudiaba las nuevas características de iOS6, recibí una pregunta sobre UICollectionView .
Actualmente estoy probándolo con el diseño de flujo y la dirección de desplazamiento establecida en horizontal, desplazamiento y paginación habilitados. Establecí su tamaño exactamente igual que las celdas de mi personalización, por lo que puede mostrarse de a una por vez, y al desplazarlo lateralmente, el usuario puede ver las otras celdas existentes.

Funciona perfectamente

Ahora quiero agregar y UIPageControl a la vista de colección que hice, para que pueda mostrar qué celda está visible y cuántas celdas hay.

La creación del control de página era bastante simple, se definieron frame y numberOfPages.

El problema que estoy teniendo, como las marcas de los títulos de pregunta, es cómo obtener qué celda está actualmente visible en la vista de colección, por lo que puede cambiar la página actual del control de página.

Probé métodos de delegado, como cellForItemAtIndexPath, pero está hecho para cargar celdas, no para mostrarlas. didEndDisplayingCell se dispara cuando ya no se muestra una celda, el evento opuesto a lo que necesito.

Parece que -visibleCells y -indexPathsForVisibleItems, métodos de vista de colección, son la opción correcta para mí, pero me topé con otro problema. ¿Cuándo dispararlos?

Gracias de antemano, espero haber sido lo suficientemente claro para que ustedes puedan entenderme!


  1. Coloque PageControl en su vista o configurado por Código.
  2. Establecer UIScrollViewDelegate
  3. En Collectionview -> cellForItemAtIndexPath (Method) agregue el siguiente código para calcular el número de páginas,

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

Agregue el método ScrollView Delegate ,

pragma mark - UIScrollVewDelegate para 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); }


Luché con esto por un tiempo también, luego me recomendaron ver las clases principales de UICollectionView. Uno de ellos pasa a ser UIScrollView y si se configura como UIScrollViewDelegate , obtiene acceso a métodos muy útiles como scrollViewDidEndDecelerating , un excelente lugar para actualizar UIPageControl.


Otra opción con menos código es usar la ruta del índice del elemento visible y establecer el control de la página.

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { self.pageControl.currentPage = [[[self.collectionView indexPathsForVisibleItems] firstObject] row]; }


Recomendaría un poco de cálculo y manejo adaptados, ya que actualizará el control de página inmediatamente en cualquier posición de desplazamiento con mayor precisión.

La solución a continuación funciona con cualquier vista de desplazamiento o subclase (UITableView UICollectionView y otros)

en el método viewDidLoad escribe esto

scrollView.delegate = self

luego usa el código para tu idioma:

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) }

C objetivo

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


Sé que este es uno antiguo, pero solo he necesitado implementar este tipo de característica nuevamente y tengo un poco que agregar que da una respuesta más completa.

En primer lugar: al usar scrollViewDidEndDecelerating supone que el usuario levantó el dedo mientras lo arrastraba (más como una acción de deslizamiento) y, por lo tanto, hay una fase de desaceleración. Si el usuario se arrastra sin levantar el dedo, UIPageControl seguirá indicando la página anterior desde antes de que comenzara el arrastre. En su lugar, el uso de la scrollViewDidScroll llamada scrollViewDidScroll significa que la vista se actualiza después de arrastrar y sacudir y también durante el arrastre y el desplazamiento, por lo que se siente mucho más receptivo y preciso para el usuario.

En segundo lugar: confiar en el pagewidth de pagewidth para calcular el índice seleccionado supone que todas las celdas tienen el mismo ancho y que hay una celda por pantalla. aprovechando el método indexPathForItemAtPoint en UICollectionView da un resultado más flexible que funcionará para diferentes diseños y tamaños de celda. La implementación a continuación asume que el centro del cuadro es la celda deseada que se representará en el pagecontrol . Además, si hay espaciado entre celdas, habrá momentos durante el desplazamiento cuando el Índice seleccionado podría ser nulo u opcional, por lo que deberá verificarlo y desenvolverlo antes de configurarlo en 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 } }

Una cosa más: configure el número de páginas en UIPageControl con algo como esto:

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


Simple Swift

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

UIScrollViewDelegate ya está implementado si implementa UICollectionViewDelegate


Debe configurar usted mismo como UIScrollViewDelegate e implementar el método scrollViewDidEndDecelerating: así:

C objetivo

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

Rápido

func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { let pageWidth = self.collectionView.frame.size.width pageControl.currentPage = Int(self.collectionView.contentOffset.x / pageWidth) }