2 votes

Comment filtrer les événements tactiles pour un UIScrollView ?

J'ai une vue qui affiche un PDF. Il devrait être zoomable, donc j'ai également créé un UIScrollView, et dans son délégué, j'ai implémenté viewForZoomingInScrollView pour renvoyer la vue PDF. Jusqu'ici tout va bien. Cependant, lorsque l'utilisateur atteint le bord d'une page PDF zoomée, j'aimerais passer à la page suivante. Cela semble facile, mais je ne semble pas parvenir à comprendre comment le faire.

J'ai essayé quelques approches différentes:

  1. Utiliser scrollViewDidScroll pour détecter si le défilement a atteint le bord. Le problème ici est que si le zoomScale est de 1, et donc le défilement n'est pas possible, cette fonction n'est jamais appelée. Mais l'UIScrollView continue tout de même de consommer tous les événements tactiles, donc je ne peux pas non plus détecter l'atteinte du bord dans touchesMoved. Définir canCancelContentTouches sur NO lorsque le zoom n'est pas activé n'est pas une option, car cela empêcherait également le zoom.

  2. Sous-classer UIScrollView, et transférer certains des événements tactiles au prochain répondant. Malheureusement, lorsque UIScrollView détecte une opération de glissement et annule le toucher, touchesMoved et touchesEnded ne sont pas appelés même pour la sous-classe UIScrollView. Encore une fois, définir canCancelContentTouches sur NO n'est pas une bonne option, car cela empêcherait également certaines fonctionnalités souhaitées de UIScrollView.

  3. Créer une vue transparente au-dessus de la vue défilante (en tant que frère de celle-ci), de sorte que cette vue reçoive tous les événements tactiles en premier, puis transmettre certains des touchers à la vue défilante. Malheureusement, la vue défilante ne répond pas à ces appels.

  4. Je ne peux pas utiliser touchesShouldCancelInContentView, car cela ne reçoit pas les touches réelles en argument, et que la réaction de la vue défilante aux événements tactiles dépend également des propriétés de l'événement tactile lui-même (par exemple, un mouvement tactile dans une direction où nous sommes déjà au bord ne devrait pas être annulé par la vue défilante, mais un mouvement dans l'autre direction pourrait l'être).

Il semblerait que quoi que ce soit que UIScrollView fait n'est pas initié par touchesBegan / touchesMoved, mais plutôt il reçoit des notifications sur les touches bien avant cela. Peut-être d'une manière non documentée que je ne peux pas intercepter, ni reproduire.

Alors y a-t-il un moyen d'être notifié de tous les mouvements tactiles effectués sur un UIScrollView, tout en pouvant toujours utiliser (lorsque certaines conditions s'appliquent) l'UIScrollView pour le zoom et le défilement?

0voto

imre Points 543

D'accord, voici ce que j'ai fait finalement :

  • Laisser tout le défilement et le zoom à UIScrollView, et gérer le changement de page dans la fonction scrollViewDidEndDragging:willDecelerate: de UIScrollViewDelegate est presque une solution, sauf que cette fonction n'est jamais appelée si tout le contenu est à l'écran, donc le glisser / défilement n'est pas possible.

  • Les balayages dans ce cas sont gérés dans les fonctions touchesBegan / touchesEnded d'un ViewController, mais pour que cela fonctionne, nous devons nous assurer que UIScrollView n'annule pas ces événements. Cependant, dans d'autres cas, UIScrollView devrait pouvoir annuler les touches pour pouvoir zoomer et défilement.

  • UIScrollView devrait pouvoir annuler les touches si:

    • Le défilement est possible (et nécessaire) car tout le contenu ne rentre pas sur l'écran (zoomScale > 1 dans mon cas), SOIT
    • L'utilisateur a touché l'écran avec deux doigts, pour que le zoom avant et arrière fonctionne.
  • Lorsque le défilement n'est pas possible, et que l'utilisateur a touché l'écran une seule fois, alors les touches ne doivent pas être annulées, et les événements tactiles doivent être transmis au contrôleur de vue.

  • Donc j'ai créé une sous-classe UIScrollView.

  • Cette sous-classe a une propriété pointant vers le ViewController.

  • En utilisant les méthodes touchesXXX, je tiens compte du nombre de touches actuelles.

  • Je transmets tous les événements tactiles au ViewController.

  • Et enfin, j'ai remplacé touchesShouldCancelInContentView:, et je renvoie NON lorsque le zoomScale est <= 1 et que le nombre de touches est de 1.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X