5

有没有办法改变 contentOffset 动画速度,而无需创建自己的设置 contentOffset 的动画?

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

4

4 回答 4

12

不幸的是,没有干净简单的方法可以做到这一点。这是一个稍微残酷但有效的方法:

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类似的变化:

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

- (void)_handleContentOffsetChangeWithOffset:(CGPoint)offset {
    // handle offset change
}
于 2014-01-18T15:09:39.680 回答
2

要获取有关滚动状态的定期信息,您可以分步运行动画。每个步骤都会调用一次委托 (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
于 2013-03-03T21:02:45.107 回答
1

下面的代码解决了我的问题

CGPoint leftOffset = CGPointMake(0, 0);
          [UIView animateWithDuration:.5
                                delay:0
                              options:UIViewAnimationOptionCurveLinear
                           animations:^{
                               [self.topBarScrollView setContentOffset:leftOffset animated:NO];
                           } completion:nil];
于 2017-01-19T07:48:31.327 回答
-3

这是一个有效的简单解决方案。

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

希望这可以帮助。

布赖恩

于 2013-06-05T21:26:53.743 回答