Animating UIScrollView contentInset causes jump stutter

ryanthon picture ryanthon · Sep 26, 2014 · Viewed 20.9k times · Source

I implemeted a custom refresh control (my own class, not a subclass), and for some reason since moving to iOS 8, setting the contentInset of the scroll view (specifically, UICollectionView) to start the refresh animation causes a weird jump/stutter. Here is my code:

- (void)containingScrollViewDidScroll:(UIScrollView *)scrollView
{
    CGFloat scrollPosition = scrollView.contentOffset.y + scrollView.contentInset.top;

    if( scrollPosition > 0 || self.isRefreshing )
    {
        return;
    }

    CGFloat percentWidth = fabs( scrollPosition ) / self.frame.size.height / 2;

    CGRect maskFrame = self.maskLayer.frame;

    maskFrame.size.width = self.imageLayer.frame.size.width * percentWidth;

    [CATransaction begin];
    [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
    self.maskLayer.frame = maskFrame;
    [CATransaction commit];
}

- (void)containingScrollViewDidEndDragging:(UIScrollView *)scrollView
{
    if( ( self.maskLayer.frame.size.width >= self.imageLayer.frame.size.width ) && !self.isRefreshing )
    {
        self.isRefreshing = YES;
        [self setLoadingScrollViewInsets:scrollView];
        [self startAnimation];
        [self sendActionsForControlEvents:UIControlEventValueChanged];
    }
}

- (void)setLoadingScrollViewInsets:(UIScrollView *)scrollView
{
    UIEdgeInsets loadingInset = scrollView.contentInset;
    loadingInset.top += self.frame.size.height;

    UIViewAnimationOptions options = UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionBeginFromCurrentState;

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

Basically once the user releases to refresh, I animate the contentInset to the height of the refresh control. I figure the animation would reduce stuttering/jumpiness, which it did in iOS 7. But in iOS 8, when the scrollView is released from dragging, instead of just animating to the contentInset, the scroll view content jumps down from the point of release really quickly, and then animates up smoothly. I'm not sure if this is a bug in iOS 8 or what. I've also tried adding:

scrollView.contentOffset = CGPointZero;

in the animation block, which didn't change anything.

Does anyone have any ideas? Any help would be highly appreciated. Thanks!

Answer

ryanthon picture ryanthon · Oct 12, 2014

I changed the method with my animation block to:

- (void)setLoadingScrollViewInsets:(UIScrollView *)scrollView
{
    UIEdgeInsets loadingInset = scrollView.contentInset;
    loadingInset.top += self.view.frame.size.height;

    CGPoint contentOffset = scrollView.contentOffset;

    [UIView animateWithDuration:0.2 animations:^
    {
        scrollView.contentInset = loadingInset;
        scrollView.contentOffset = contentOffset;
    }];
}