Programmatically triggers scrollViewDidScroll

j'ai quelques UIScrollView sur une page. Vous pouvez les faire défiler indépendamment ou les verrouiller ensemble et les faire défiler comme un seul. Le problème se produit lorsqu'ils sont verrouillés.

j'utilise UIScrollViewDelegate et scrollViewDidScroll: pour suivre le mouvement. Je pose une question sur le contentOffset du UIScrollView qui a changé puis reflète le changement à d'autres vues de défilement en définissant leur propriété contentOffset pour correspondre.

Super.... sauf que j'ai remarqué beaucoup de extra appeler. Changer programmatiquement le contentOffset de mes vues de défilement déclenche la méthode de délégué scrollViewDidScroll: à appeler. J'ai essayé d'utiliser setContentOffset:animated: à la place, mais j'ai toujours la gâchette sur le délégué.

Comment puis-je modifier mon contentOffsets programmatiquement pour ne pas déclencher scrollViewDidScroll: ?

notes de mise en Œuvre.... Chaque UIScrollView fait partie d'une coutume UIView qui utilise le motif de délégué pour rappeler à la présentation UIViewController sous-classe qui coordonne les différentes valeurs contentOffset .

50
demandé sur DBD 2012-02-23 21:45:28

6 réponses

il est possible de modifier le décalage de contenu d'un UIScrollView sans déclencher le rappel délégué scrollViewDidScroll: , en réglant les limites du UIScrollView avec l'origine réglée sur le décalage de contenu désiré.

CGRect scrollBounds = scrollView.bounds;
scrollBounds.origin = desiredContentOffset;
scrollView.bounds = scrollBounds;
100
répondu Tark 2012-02-23 18:05:05

Essayer

id scrollDelegate = scrollView.delegate;
scrollView.delegate = nil;
scrollView.contentOffset = point;
scrollView.delegate = scrollDelegate;

travaillait pour moi.

66
répondu Abhijit 2013-07-25 11:10:25

Qu'en est-il de l'utilisation des propriétés existantes D'UIScrollView?

if(scrollView.isTracking || scrollView.isDragging || scrollView.isDecelerating) {
    //your code
}
34
répondu Kukosk 2014-11-08 16:35:08

en simplifiant la réponse de @Tark, vous pouvez positionner le scrollview sans tirer scrollViewDidScroll sur une ligne comme celle-ci:

scrollView.bounds.origin = CGPoint(x:0, y:100); // whatever values you'd like
6
répondu SimplGy 2015-03-10 12:33:09

une autre approche consiste à ajouter une certaine logique dans votre scrollViewDidScroll delegate pour déterminer si oui ou non le changement de décalage de contenu a été déclenché programatiquement ou par le toucher de l'utilisateur.

  • ajouter une variable booléenne "isManualScroll" à votre classe.
  • définit sa valeur initiale à false.
  • dans scrollviewwillbegindraging l'a mis à true.
  • dans votre scrollViewDidScroll vérifiez que est-ce vrai et ne répond que si c'est le cas?
  • dans scrollviewdidenddedecelerating le met à false.
  • dans scrollviewwillenddraging ajoute de la logique pour la mettre à false si la vitesse est 0 (comme scrollViewDidEndDecelerating ne sera pas appelé dans ce cas).
5
répondu Jake MacMullin 2014-09-11 01:39:33

ce n'est pas une réponse directe à la question, mais si vous recevez ce qui semble être de faux messages de ce genre, cela peut aussi être parce que vous changez les limites. J'utilise un code D'échantillon D'Apple avec une méthode de "tilePages" qui supprime et ajoute subview à un scrollview. Cela résulte rarement en scrollViewDidScroll supplémentaire: messages appelés immédiatement, de sorte que vous obtenez dans une récursion que vous ne vous attendiez certainement pas. Dans mon cas, j'ai eu un méchant impossible de trouver la panne.

ce que j'ai fini par faire était de faire la file d'attente sur la file d'attente principale:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if(scrollView == yourScrollView) {
        // dispatch fixes some recursive call to scrollViewDidScroll in tilePages (related to removeFromSuperView)
        // The reason can be found here: http://stackoverflow.com/questions/9418311
        dispatch_async(dispatch_get_main_queue(), ^{ [self tilePages]; });
    }
}
4
répondu David H 2012-03-31 21:00:26