objective c - UIScrollView setContentInset provoque un saut de défilement dans ios8



objective-c (2)

J'ai un problème lors de la création d'un pull to refresh mécanisme au bas d'un scrollview. Le code fonctionne parfaitement dans iOS7, mais dans iOS8, le scrollview saute instantanément avant d'animer la bonne position.

Je suis en train de suivre le défilement jusqu'à ce qu'il ait été bandé au-delà de kPullToRefreshHeightPX (dans mon cas, il s'agit de 40px), et de définir un drapeau pour ensuite l'insérer à la publication et déclencher un rafraîchissement du contenu.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (_webShouldInsetScrollView == NO && (scrollView.contentOffset.y > ((scrollView.contentSize.height - scrollView.frame.size.height) + kPullToRefreshHeightPX)))
    {
        _webShouldInsetScrollView = YES;
    }
}

Si à la fin du glissement nous avons traîné au-delà de notre distance de rafraîchissement, nous insérons (et exécutons notre petite animation de rafraîchissement) et montrons la page de résultats suivante.

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    if (_webShouldInsetScrollView)
    {
        [UIView animateWithDuration:0.2 animations:^{
                [scrollView setContentInset:UIEdgeInsetsMake(0.0f, 0.0f, kPullToRefreshHeightPX, 0.0f)];
        } completion:^(BOOL finished) {
        }];

        [self performSelector:@selector(showNextResultsPage) withObject:nil afterDelay:1.0f];
    }
}

J'ai lu d'autres problèmes avec UIScrollViews dans iOS8, dont l'un indiquait que automaticallyAdjustsScrollViewInsets avait la valeur false dans iOS7, mais maintenant true par défaut dans iOS8, mais cela n'a aucun effet sur le code ci-dessus. Est-ce que quelqu'un d'autre a eu une expérience similaire et a fait un tour?

https://src-bin.com


Answer #1

Après avoir cherché pendant un certain temps, je ne trouve pas la réponse appropriée. Et en regardant plusieurs implémentations pull-to-referh du github (les exécutant dans le simulateur iOS8), je peux voir que tous montrent exactement le même saut sur iOS8.

Voici ce que j'ai pu faire pour minimiser cet effet. Pour récapituler le problème: lorsque notre contrôle d'actualisation doit rester visible, nous essayons d'ajuster contentInset en contentInset de la valeur de notre hauteur de contrôle dans le scrollView . La modification de contentInset déclenche le défilement du contenu (sur iOS7 et iOS8) et sur iOS8, ce saut est assez visible.

J'ai enlevé tout changement dans contentInset de la fonction de startRefresh de pull-to-refres. Dans votre cas, supprimez toute UIView animateWithDuration:0.2 animations partir de scrollViewDidEndDragging .

Et ajoutez quelque chose comme ça dans le gestionnaire scrollViewDidScroll (début de celui-ci):

if (self.isRefreshing) {
    // If we already scrolled back past the point of our control height and we haven't changed
    // contentInset yet - update it

    if (scrollView.contentOffset.y > -CONTROL_HEIGHT && scrollView.contentInset.top == 0) {
        UIEdgeInsets inset = scrollView.contentInset;
        inset.top = CONTROL_HEIGHT;
        scrollView.contentInset = inset;
    }
    return;
}

... 

Answer #2

Nous avons exactement le même problème ...

Après avoir creusé plus profond j'ai vu, que d'une façon ou d'une autre l'encart cible est placé quelque part:

disons que je descends la tableView de 200 à 500 - sur scrollViewDidEndDragging je déclenche l'animation comme ceci:

 [UIView animateWithDuration:0.2
                          delay:0
                        options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState
                     animations:^{
                         scrollView.contentInset = targetInset;
                     }
                     completion:nil];

    [self sendActionsForControlEvents:UIControlEventValueChanged];

Au lieu d'animer doucement à partir de 500 vers -let's dis-250, le targetValue (250) est défini une fois avant que les valeurs animées correctes soient définies ...

Ma solution de contournement a été de définir un drapeau d'animation avant de démarrer l'animation. Je l'ai réinitialisé dans le bloc complet ... Le scroller vérifie cet indicateur et ne définit la valeur targetValue que si l'animation est terminée:

_isAnimatingInset = YES;
_currentTopInsetTarget = targetInset.top;

 [UIView animateWithDuration:0.2
                          delay:0
                        options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState
                     animations:^{
                         scrollView.contentInset = targetInset;
                     }
                     completion:^(BOOL finished) {
                         //Workaround for a iOS8-Bug see property-comment for further infos
                         _isAnimatingInset = NO;
                         scrollView.contentInset = targetInset;
                     }];

    [self sendActionsForControlEvents:UIControlEventValueChanged];

Cela minimise l'effet, mais malheureusement à ce moment je ne peux pas empêcher le réglage de cette fausse valeur (à la place je la réinitialise à la précédente ce qui conduit aussi à un petit hickUp dans l'animation ...)





ios8