web-dev-qa-db-fra.com

Problème avec uiscrollview setcontentoffset animé ne défilant pas lorsque animé: oui est défini

C'est très étrange et je me demande si quelqu'un a des idées? 

J'essaie de faire défiler un UIScrollView en réponse à une pression sur un bouton de l'iPad. 

Si je fais:

CGPoint currentOff = scrollView.contentOffset;
currentOff.x+=240;
[scrollView setContentOffset:currentOff animated: NO];

La vue de défilement passe à la position requise comme prévu, mais je souhaite le faire défiler. Cependant, quand je le fais:

CGPoint currentOff = scrollView.contentOffset;
currentOff.x+=240;
[scrollView setContentOffset:currentOff animated: YES];

Alors ça ne fait rien! J'ai une autre vue de défilement qui fonctionne correctement et qui répond à setContentOffset:YES comme prévu, alors je suis assez perplexe. Toutes les idées sur pourquoi le défilement pourrait ne pas arriver sont les bienvenues!

De plus, - (void)scrollViewDidScroll:(UIScrollView *)sender ne reçoit rien du tout lorsque animated:YES est utilisé mais est appelé lorsque animated:NO est utilisé!

42
BountyBob

Cela m'est arrivé aussi et j'ai fini par faire cette solution de contournement:

[UIView animateWithDuration:.25 animations:^{
    self.scrollView.contentOffset = ...;
}];
79

D'après mon expérience personnelle, ce problème se produit lorsque setContentOffset: est appelé plusieurs fois avant que l'animation ait eu la chance de s'exécuter.

Je ne suis pas totalement au courant du problème, mais je crois que le problème se pose comme suit:

setContentOffset: animation est appelée qui définit la nouvelle valeur de décalage . setContentOffset: appelle ensuite avec les mêmes paramètres, ce qui annule l'animation. Il remarque également que les nouveaux paramètres sont les mêmes que les anciens paramètres et suppose donc que rien n’a à être fait, même si l’animation n’a pas encore été exécutée.

La solution ci-dessus rompt en quelque sorte ce cycle, mais une solution moins efficace consiste peut-être à définir des points de rupture dans le code et à éliminer les appels multiples.

7
aepryus

Difficile à dire avec ce morceau de code que vous avez donné. Et en fait, si vous dites que vous avez un projet, où tout fonctionne dans les mêmes conditions, les conditions ne sont évidemment pas les mêmes :) Je ne pourrais pas reproduire le problème, mais voici quelques hypothèses pour 2 cas:

  1. Création de UIScrollView avec nib.

    • N'oubliez pas de créer IBOutlet et de le lier à l'élément scrollView de nib. Dans une application basée sur une vue simple, juste après cela, scrollView fonctionnait comme vous le souhaitiez en animation: YES et NO. Mais pour faire du travail 

    -(void)scrollViewDidScroll:(UIScrollView *)sender; vous devez définir le délégué:

yourScrollView.delegate = self;

où 'self' est class, où vous avez votre fonction scrollViewDidScroll; Au fait, cette classe doit être conforme au protocole 'UIScrollViewDelegate'.

2.Création manuelle de l'objet UIScrollView.

  • ici, l’idée est fondamentalement la même, je vais donc vous fournir un code simple:

    -(void) creatingScrollView {
        UIScrollView *newScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(20, 5, 280, 44)];
        newScroll.pagingEnabled = YES;
        newScroll.showsVerticalScrollIndicator = NO;
        newScroll.showsHorizontalScrollIndicator = NO;
    
        // ... some subviews being added to our scroll view
    
        newScroll.delegate = self;
        [self.view addSubview:newScroll];
        [newScroll release];
    }
    

Cela fonctionne pour moi. J'espère que c'est utile.

2
makaron

Je travaille avec des vues de table, car la solution d'aepryus dit: setContentOffset: est appelé simultanément avec d'autres animations.

Dans mon cas, je viens d'inverser ces commandes:

[tableView reloadData];
[tableView setContentOffset:CGPointMake(240, 0) animated:FALSE];

comme ça

[tableView setContentOffset:CGPointMake(240, 0) animated:FALSE];
[tableView reloadData];

L'animation commence après le décalage du contenu.

1
Marco

Solution pour Xamarin.iOS

InvokeOnMainThread(() =>
{
  scrollView.SetContentOffset(new PointF((page * UIScreen.MainScreen.Bounds.Width), 0), true);
});

Ceci peut également être résolu en utilisant UIView.Animate

UIView.Animate(
    duration: .25,
    animation: () =>
    {
       scrollView.SetContentOffset(new PointF((value * UIScreen.MainScreen.Bounds.Width), 0), true);
    }
);
1
ben

Tu pourrais essayer:

[scrollView setContentOffset:CGPointMake(240, 0) animated:YES];
0
mtompson

J'avais le même problème, dans mon cas j'interceptais aussi:

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {...}

Cette méthode est appelée immédiatement après: (Elle n'attend pas la fin de l'animation):

[scrollView setContentOffset:currentOff animated: YES];

Ce qui signifie que si vous avez une logique qui "attend" la fin de l'animation et que vous interceptez scrollViewDidEndScrollingAnimation, le résultat sera indéfini, c'est-à-dire que IE: met fin à l'animation prématurément.

EDIT: La solution acceptée/solution de contournement:

[UIView animateWithDuration:.25 animations:^{
    self.scrollView.contentOffset = ...;
}];

Également "fonctionne" dans mon scénario car définir directement le contentOffset n'invoque pas scrollViewDidEndScrollingAnimation

0
Dado

Je suis confronté au même problème que ScrollView ne défile pas… .. Et j'ai désactivé «Utiliser la mise en page automatique» dans la vue, puis ScrollView fonctionne.

0
ChengChieh
func scrollViewDidScroll(scrollView: UIScrollView) {

    dispatch_async(dispatch_get_main_queue(),{

        UIView.animateWithDuration(0.10, animations: { () -> Void in

            let loginScrollViewCurrentPosition:CGPoint = CGPointMake(self.loginScrollView.contentOffset.x, self.loginScrollView.contentOffset.y) as CGPoint
            self.loginScrollView.setContentOffset(loginScrollViewCurrentPosition, animated: true)

            })
    })

}
0
A.G