web-dev-qa-db-fra.com

La définition de contentOffset déclenche par programme 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 recherche le contentOffset du UIScrollView qui a changé, puis je reflète les modifications apportées aux autres vues de défilement en définissant leur propriété contentOffset pour qu'elles correspondent.

Super .... sauf que j'ai remarqué beaucoup d'appels supplémentaires. La modification par programme du contentOffset de mes vues de défilement déclenche la méthode déléguée scrollViewDidScroll: être appelé. J'ai essayé d'utiliser setContentOffset:animated: à la place, mais je reçois toujours le déclencheur sur le délégué.

Comment puis-je modifier mes contentOffsets par programmation pour ne pas déclencher scrollViewDidScroll:?

Notes d'implémentation .... Chaque UIScrollView fait partie d'un UIView personnalisé qui utilise un modèle délégué pour rappeler à la sous-classe UIViewController de présentation qui gère la coordination des divers contentOffset valeurs.

59
DBD

Il est possible de modifier le décalage de contenu d'un UIScrollView sans déclencher le rappel du délégué scrollViewDidScroll:, en définissant les limites de UIScrollView avec l'Origine défini sur le décalage de contenu souhaité.

CGRect scrollBounds = scrollView.bounds;
scrollBounds.Origin = desiredContentOffset;
scrollView.bounds = scrollBounds;
106
Tark

Essayer

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

A travaillé pour moi.

76
Abhijit

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

if(scrollView.isTracking || scrollView.isDragging || scrollView.isDecelerating) {
    //your code
}
38
Kukosk

En simplifiant la réponse de @ Tark, vous pouvez positionner la vue de défilement sans tirer scrollViewDidScroll sur une seule ligne comme ceci:

scrollView.bounds.Origin = CGPoint(x:0, y:100); // whatever values you'd like
6
SimplGy

Une autre approche consiste à ajouter de la logique dans votre délégué scrollViewDidScroll pour déterminer si la modification de l'offset de contenu a été déclenchée par programme ou par le toucher de l'utilisateur.

  • Ajoutez une variable booléenne "isManualScroll" à votre classe.
  • Définissez sa valeur initiale sur false.
  • Dans scrollViewWillBeginDragging, définissez-le sur true.
  • Dans votre scrollViewDidScroll, vérifiez que c'est vrai et ne répondez que si c'est le cas.
  • Dans scrollViewDidEndDecelerating, définissez-le sur false.
  • Dans scrollViewWillEndDragging, ajoutez une logique pour la définir sur false si la vitesse est 0 (car scrollViewDidEndDecelerating ne sera pas appelé dans ce cas).
5
Jake MacMullin

Ce n'est pas une réponse directe à la question, mais si vous obtenez ce qui semble être de faux messages, cela peut également être parce que vous changez les limites. J'utilise certains Apple exemple de code avec une méthode "tilePages" qui supprime et ajoute une sous-vue à une vue de défilement. à coup sûr, je ne m'y attendais pas.

J'ai fini par mettre l'appel en 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
David H