如何更改UIScrollView contentOffset动画速度?

问题描述:

有没有办法改变contentOffset动画速度而不创建自己的动画来设置contentOffset?如何更改UIScrollView contentOffset动画速度?

我无法为contentOffset更改创建自己的动画的原因是,在动画期间,它不会定期调用-scrollViewDidScroll:。

+1

假设调用'[滚动视图setContentOffset:FOO动画:是]'从内的动画块不工作(我怀疑事实并非如此),则很可能通过搞乱访问动画持续时间“私人“的API - 例如[这个答案](http://stackoverflow.com/a/11271360/349112)给出了一种方法来改变减速率。这里是龙... – 2013-03-03 19:12:46

+0

嗨,请看下面我修改的答案。 – danh 2013-03-04 06:02:09

要获取有关滚动状态的定期信息,您可以分步运行动画。代表将被调用一次(scrollViewDidScroll :)每一步

- (void)scrollTo:(CGPoint)offset completion:(void (^)(BOOL))completion { 

    // this presumes an outlet called scrollView. You could generalize by passing 
    // the scroll view, or even more generally, place this in a UIScrollView category 
    CGPoint contentOffset = self.scrollView.contentOffset; 

    // scrollViewDidScroll delegate will get called 'steps' times 
    NSInteger steps = 10; 
    CGPoint offsetStep = CGPointMake((offset.x-contentOffset.x)/steps, (offset.y-contentOffset.y)/steps); 
    NSMutableArray *offsets = [NSMutableArray array]; 

    for (int i=0; i<steps; i++) { 
     CGFloat stepX = offsetStep.x * (i+1); 
     CGFloat stepY = offsetStep.y * (i+1); 
     NSValue *nextStep = [NSValue valueWithCGPoint:CGPointMake(contentOffset.x+stepX, contentOffset.y+stepY)]; 
     [offsets addObject:nextStep]; 
    } 
    [self scrollBySteps:offsets completion:completion]; 
} 

// run several scroll animations back-to-back 
- (void)scrollBySteps:(NSMutableArray *)offsets completion:(void (^)(BOOL))completion { 

    if (!offsets.count) return completion(YES); 

    CGPoint offset = [[offsets objectAtIndex:0] CGPointValue]; 
    [offsets removeObjectAtIndex:0]; 

    // total animation time == steps * duration. naturally, you can fool with both 
    // constants. to keep the rate constant, set duration == steps * k, where k 
    // is some constant time per step 
    [UIView animateWithDuration:0.1 delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{ 
     self.scrollView.contentOffset = offset; 
    } completion:^(BOOL finished) { 
     [self scrollBySteps:offsets completion:completion]; 
    }]; 
} 

这样称呼它......

CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height);  
[self scrollTo:bottomOffset completion:^(BOOL finished) {}]; 

// BONUS completion handler! you can omit if you don't need it 
+2

我试过了,它非常波涛汹涌! – brenjt 2013-08-01 21:32:54

+1

+1波涛汹涌:-) – 2014-10-21 16:13:33

这里有一个简单的解决方案,它的工作原理。

[UIView beginAnimations:nil context:nil]; 
    [UIView setAnimationDuration:0.5]; 
    [self setContentOffset:<offset> animated:YES]; 
    [UIView commitAnimations]; 

希望这有助于。

布赖恩

+1

不起作用。尝试设置不同的持续时间,它仍然约500毫秒。 – jede 2013-11-15 14:51:26

不幸的是没有干净,简单的方法来做到这一点。 这里有一个稍微残酷的,但工作方式:

1)添加CADisplayLink作为一个属性:

@property (nonatomic, strong) CADisplayLink *displayLink; 

2)动画内容偏移:

CGFloat duration = 2.0; 

// Create CADisplay link and add it to the run loop 
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_displayLinkTick)]; 
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 

[UIView animateWithDuration:duration animations:^{ 
    self.scrollView.contentOffset = newContentOffset;  
} completion:^(BOOL finished) { 
    // Cleanup the display link 
    [self.displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 
    self.displayLink = nil; 
}]; 

3)最后上观察其变化presentationLayer like:

- (void)_displayLinkTick { 
    CALayer *presentationLayer = (CALayer *)self.scrollView.layer.presentationLayer; 
    CGPoint contentOffset = presentationLayer.bounds.origin; 
    [self _handleContentOffsetChangeWithOffset:contentOffset]; 
} 

- (void)_handleContentOffsetChangeWithOffset:(CGPoint)offset { 
    // handle offset change 
} 
+0

我认为步骤3是最重要的一点:UI的当前状态由presentationLayer给出。 – 2014-10-22 09:34:19

+1

@kamilkocemba这是一个惊人的技巧!这实际上是一种使用单个动画来驱动其他元素位置的非常有效的方法。谢谢! – 2014-11-03 16:56:38

+0

它的作品。但是UIScrollView上的任何按钮都不会收到触摸事件。 – Asfanur 2015-05-08 08:41:15

下面的代码解决了我的i ssue

CGPoint leftOffset = CGPointMake(0, 0); 
      [UIView animateWithDuration:.5 
           delay:0 
           options:UIViewAnimationOptionCurveLinear 
          animations:^{ 
           [self.topBarScrollView setContentOffset:leftOffset animated:NO]; 
          } completion:nil];