UIScrollview setContentOffset with non linear animation?

I am trying to reproduce the smooth animation of a scrollview with paging enabled when you actually scroll to the next page. It seems to be UIViewAnimationCurveEaseInOut, but I need to have a “next page” button and trig the scroll programmatically.

Here is my code :

  • UIScrollview content size when orientation changes
  • UIScrollView image/photo viewer with paging enabled and zooming
  • Dismissing the keyboard in a UIScrollView
  • Why won't UIScrollView scroll fully after adding objects? Using storyboard, ARC, and Xcode 4.5.2
  • In iOS 4.0, why does UIScrollView zoomToRect:animated: not trigger the scrollViewDidScroll or scrollViewDidZoom delegates while animating?
  • iOS/Swift - Hide/Show UITabBarController when scrolling down/up
  • -(void) scrollToPage:(int)page
    {
        UIScrollView *scrollView = contentView;
        CGPoint offset = CGPointMake(scrollView.bounds.size.width * page, scrollView.contentOffset.y);
        [scrollView setContentOffset:offset animated: YES];     
        [self pageControlUpdate];
    }
    
    -(void) scrollToNextPage 
    {
        [self scrollToPage:(pageControl.currentPage + 1)];
    }
    

    I cannot manage to reproduce the smoothness of UIViewAnimationCurveEaseInOut,
    either with setContentOffset, or with scrollRectToVisible
    it goes to the next page with an ugly linear animation

    I even tried to animate it manually :

    [UIView animateWithDuration:.5 delay:0 options:UIViewAnimationCurveEaseInOut animations:^{
        scrollView.contentOffset = offset;
    } completion:^(BOOL finished) {    } ];
    

    where am I wrong ?

    4 Solutions Collect From Internet About “UIScrollview setContentOffset with non linear animation?”

    Every time you make your own animations you have to pass NO as animated: parameter:

    - (void)scrollToPage:(int)page
    {
        UIScrollView *scrollView = contentView;
        CGPoint offset = CGPointMake(scrollView.bounds.size.width * page, 
                                     scrollView.contentOffset.y);
    
        [UIView animateWithDuration:.5
                              delay:0
                            options:UIViewAnimationCurveEaseInOut
                         animations:^{
                             [scrollView setContentOffset:offset animated:NO];
                         } completion:nil];
    
        [self pageControlUpdate];
    }
    

    With the use of public APIs, I don’t believe this is currently possible. Assuming you don’t need user interaction during the course of the animation, you’d be better off animating the position of your UIScrollView‘s subviews (ie. the scroll view’s content) instead, and then adjusting the contentOffset without animation on completion. You could do it like so:

    - (void) scrollToPage:(int)page {
        UIScrollView *scrollView = contentView;
        scrollView.userInteractionEnabled = NO;
        CGPoint offset = CGPointMake(scrollView.bounds.size.width * page, scrollView.contentOffset.y);
        CGFloat delta = offset.x - scrollView.contentOffset.x;
    
        __block int animationCount = 0;
        for (UIView *view in scrollView.subviews) {
            [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
                animationCount++;
                CGRect frame = view.frame;
                frame.origin.x -= delta;
                view.frame = frame;
            } completion:^(BOOL finished) {
                animationCount--;
                if (animationCount == 0) {
                    scrollView.contentOffset = offset;
                    for (UIView *view in scrollView.subviews) {
                        CGRect frame = view.frame;
                        frame.origin.x += delta;
                        view.frame = frame;
                    }
                    scrollView.userInteractionEnabled = YES;
                }
            }];
        }
    }
    

    I can confirm this works as expected, I tested it myself.

    [UIView animateWithDuration:(Animation_Duration)
                              delay:0.0
                            options:UIViewAnimationOptionCurveEaseInOut
                         animations:^{
                         [scroll setContentOffset:CGPointMake(PointX, PointY) animated:NO];
                          }
                         completion:^(BOOL finished){}];`
    

    This class absolutely saved my life:

    MOScroll on GitHub.com

    It has

    - (void)setContentOffset:(CGPoint)contentOffset
    withTimingFunction:(CAMediaTimingFunction *)timingFunction
    duration:(CFTimeInterval)duration;

    Just like the private API but with all public methods and math.