Détection du changement de page UIScrollView

Existe-t-il un moyen de détecter ou d’obtenir une notification lorsque l’utilisateur modifie la page dans un UIScrollView compatible avec la pagination?

Implémentez le délégué de UIScrollView. Cette méthode est ce que vous recherchez.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView 

Utilisez cette option pour détecter la page actuellement affichée et effectuer certaines actions sur le changement de page:

 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { static NSInteger previousPage = 0; CGFloat pageWidth = scrollView.frame.size.width; float fractionalPage = scrollView.contentOffset.x / pageWidth; NSInteger page = lround(fractionalPage); if (previousPage != page) { // Page has changed, do your thing! // ... // Finally, update previous page previousPage = page; } } 

S’il est acceptable que vous scrollViewDidEndDecelerating: uniquement au changement de page une fois que le défilement est complètement arrêté, il est préférable de procéder comme ci-dessus dans la méthode scrollViewDidEndDecelerating: delegate au lieu de la méthode scrollViewDidScroll:

Dans la vue de défilement activée pour la pagination, vous pouvez utiliser scrollViewDidEndDecelerating pour savoir si la vue est réglée sur une page (peut-être la même page).

 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 

scrollViewDidScroll est appelé à chaque mouvement. Et dans le contexte de la pagination activée, la vue peut être utilisée pour rechercher le moment où elle défile suffisamment pour passer à la page suivante (si le glissement est arrêté à ce point).

Que diriez-vous de combiner deux méthodes de UIScrollViewDelegate?

Dans scrollViewDidEndDragging(_:willDecelerate:) , s’il s’arrête immédiatement, nous effectuons le calcul de la page; si elle décélère, nous la lâcherons et scrollViewDidEndDecelerating(_:) sera intercepté.

Le code est testé avec XCode version 7.1.1, version 2.1 de Swift

 class ViewController: UIViewController, UIScrollViewDelegate { // MARK: UIScrollViewDelegate func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) { if decelerate == false { let currentPage = scrollView.currentPage // Do something with your page update print("scrollViewDidEndDragging: \(currentPage)") } } func scrollViewDidEndDecelerating(scrollView: UIScrollView) { let currentPage = scrollView.currentPage // Do something with your page update print("scrollViewDidEndDecelerating: \(currentPage)") } } extension UIScrollView { var currentPage: Int { return Int((self.contentOffset.x+ (0.5*self.frame.size.width))/self.frame.width)+1 } } 

Premier résultat sur Google pour la détection de page, j’ai donc dû y répondre avec une meilleure solution à mon avis. (même si cette question a été posée il y a deux ans et demi.)

Je préférerais ne pas appeler scrollViewDidScroll juste pour suivre le numéro de page. Thats un overkill pour quelque chose de simple comme ça. L’utilisation de scrollViewDidEndDecelerating fonctionne et s’arrête sur un changement de page MAIS (et c’est un gros mais) si l’utilisateur glisse deux fois plus rapidement sur l’écran que d’habitude scrollViewDidEndDecelerating ne sera appelé qu’une seule fois. Vous pouvez facilement passer de la page n ° 1 à la page n ° 3 sans traiter la page n ° 2.

Cela l’a résolu complètement pour moi:

 - (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView { scrollView.userInteractionEnabled = NO; } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { //Run your code on the current page scrollView.userInteractionEnabled = YES; } 

De cette façon, l’utilisateur ne peut glisser qu’une page à la fois sans le risque décrit ci-dessus.

Rapide 4

J’ai trouvé le meilleur moyen de le faire en utilisant scrollViewWillEndDragging(_:withVelocity:targetContentOffset:) . Il vous permet de prédire si la pagination se produira dès que vous relèverez votre doigt de l’écran. Cet exemple concerne la pagination horizontale.

N’oubliez pas d’affecter le scrollView.delegate à l’object qui adopte UIScrollViewDelegate et implémente cette méthode.

 var previousPageXOffset: CGFloat = 0.0 func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { let targetOffset = targetContentOffset.pointee if targetOffset.x == previousPageXOffset { // page will not change } else if targetOffset.x < previousPageXOffset { // scroll view will page left } else if targetOffset.x > previousPageXOffset { // scroll view will page right } previousPageXOffset = targetOffset.x // If you want to track the index of the page you are on just just divide the previousPageXOffset by the scrollView width. // let index = Int(previousPageXOffset / scrollView.frame.width) } 

Voici la solution rapide pour cela.

Créez deux propriétés currentPage et previousPage dans la classe où vous implémentez votre code et initialisez-les à 0.

Mettez maintenant à jour currentPage à partir de scrollViewDidEndDragging ( : willDecelerate 🙂 et scrollViewDidEndDecelerating ( : scrollView :).

Et puis mettre à jour previousPage dans scrollViewDidEndScrollingAnimation (_: scrollView 🙂

  //Class Properties var currentPage = 0 var previousPage = 0 func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) { updatePage(scrollView) return } func scrollViewDidEndDecelerating(scrollView: UIScrollView){ updatePage(scrollView) return } func updatePage(scrollView: UIScrollView) { let pageWidth:CGFloat = scrollView.frame.width let current:CGFloat = floor((scrollView.contentOffset.x-pageWidth/2)/pageWidth)+1 currentPage = Int(current) if currentPage == 0 { // DO SOMETHING } else if currentPage == 1{ // DO SOMETHING } } func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) { if previousPage != currentPage { previousPage = currentPage if currentPage == 0 { //DO SOMETHING }else if currentPage == 1 { // DO SOMETHING } } }