ope*_*rog 4 core-animation uiscrollview uikit ios
有没有办法改变contentOffset动画的速度,而无需创建自己设置contentOffset的动画?
我无法为contentOffset更改创建自己的动画的原因是,这不会在动画期间以常规间隔调用-scrollViewDidScroll:
kko*_*dev 11
不幸的是,没有干净简单的方法可以做到这一点.这是一个有点残酷,但有效的方法:
1)CADisplayLink作为财产添加:
@property (nonatomic, strong) CADisplayLink *displayLink;
Run Code Online (Sandbox Code Playgroud)
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;
}];
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
要获取有关滚动状态的定期信息,您可以分步运行动画。每个步骤都会调用一次委托 (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];
}];
}
Run Code Online (Sandbox Code Playgroud)
像这样称呼它...
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
Run Code Online (Sandbox Code Playgroud)