Alex Rivera | Logout

Change the speed of setContentOffset:animated:?

Asked 2010-12-10T01:06:17.677
47

Is there a way to change the speed of the animation when scrolling a UITableView using setContentOffset:animated:? I want to scroll it to the top, but slowly. When I try the following, it causes the bottom few cells to disappear before the animation starts (specifically, the ones that won't be visible when the scroll is done):

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:3.0];
[self.tableView setContentOffset:CGPointMake(0, 0)];
[UIView commitAnimations];

Any other way around this problem? There is a private method _setContentOffsetAnimationDuration that works, but I don't want to be rejected from the app store.

Edit
Report

2 Answers

14

I've taken nacho4d's answer and implemented the code, so I thought it would be helpful for other people coming to this question to see working code:

I added member variables to my class:

CGPoint startOffset;
CGPoint destinationOffset;
NSDate *startTime;

NSTimer *timer;

and properties:

@property (nonatomic, retain) NSDate *startTime;
@property (nonatomic, retain) NSTimer *timer;

and a timer callback:

- (void) animateScroll:(NSTimer *)timerParam
{
    const NSTimeInterval duration = 0.2;

    NSTimeInterval timeRunning = -[startTime timeIntervalSinceNow];

    if (timeRunning >= duration)
    {
        [self setContentOffset:destinationOffset animated:NO];
        [timer invalidate];
        timer = nil;
        return;
    }
    CGPoint offset = [self contentOffset];

    offset.x = startOffset.x +
        (destinationOffset.x - startOffset.x) * timeRunning / duration;

    [self setContentOffset:offset animated:NO];
}

then:

- (void) doAnimatedScrollTo:(CGPoint)offset
{
    self.startTime = [NSDate date];
    startOffset = self.contentOffset;
    destinationOffset = offset;

    if (!timer)
    {
        self.timer = [NSTimer scheduledTimerWithTimeInterval:0.01
                                                      target:self
                                                    selector:@selector(animateScroll:)
                                                    userInfo:nil
                                                     repeats:YES];
    }
}

you'd also need timer cleanup in the dealloc method. Since the timer will retain a reference to the target (self) and self has a reference to the timer, some cleanup code to cancel/destroy the timer in viewWillDisappear is likely to be a good idea too.

Any comments on the above or suggestions for improvement would be most welcome, but it is working very well with me,

answered 2011-02-11T18:40:06.007
1

IF all your trying to do is scroll your scrollview I think you should use scroll rect to visible. I just tried out this code

 [UIView animateWithDuration:.7
                      delay:0
                    options:UIViewAnimationOptionCurveEaseOut
                 animations:^{  
                     CGRect scrollToFrame = CGRectMake(0, slide.frame.origin.y, slide.frame.size.width, slide.frame.size.height + kPaddingFromTop*2);
                     CGRect visibleFrame = CGRectMake(0, scrollView.contentOffset.y,
                                                      scrollView.frame.size.width, scrollView.frame.size.height);
                     if(!CGRectContainsRect(visibleFrame, slide.frame))
                         [self.scrollView scrollRectToVisible:scrollToFrame animated:FALSE];}];

and it scrolls the scrollview to the location i need for whatever duration i am setting it for. The key is setting animate to false. When it was set to true, the animation speed was the default value set by the method

answered 2013-02-20T15:08:08.033

Your Answer