我认为这是你最好自己做的事情。创建一个适当的库来为数据设置动画可能需要几个小时,但最终它会是非常有益的。
需要几个组件:
有时间限制的动画应该包括 aCADispalyLink
或 a NSTimer
。创建一个公共方法,例如animateWithDuration:
它将启动计时器、记录当前日期并设置目标日期。插入一个浮点值作为属性,然后将其从 0 插入到 1 到日期。很可能看起来像这样:
- (void)onTimer {
NSDate *currentTime = [NSDate date];
CGFloat interpolation = [currentTime timeIntervalSinceDate:self.startTime]/[self.targetTime timeIntervalSinceDate:self.startTime];
if(interpolation < .0f) { // this could happen if delay is implemented and start time may actually be larger then current
self.currentValue = .0f;
}
else if(interpolation > 1.0f) { // The animation has ended
self.currentValue = 1.0f;
[self.displayLink invalidate]; // stop the animation
// TODO: notify owner that the animation has ended
}
else {
self.currentValue = interpolation;
// TODO: notify owner of change made
}
}
正如您从评论中看到的那样,您应该在此方法中再调用 2 次,这将通知所有者/侦听器动画的更改。这可以通过委托、块、调用、目标选择器对来实现……
所以此时你有一个在 0 和 1 之间插值的浮点值,现在可以用来插值你想要可见的矩形。这是一个非常简单的方法:
- (CGRect)interpolateRect:(CGRect)source to:(CGRect)target withScale:(CGFloat)scale
{
return CGRectMake(source.origin.x + (target.origin.x-source.origin.x)*scale,
source.origin.y + (target.origin.y-source.origin.y)*scale,
source.size.width + (target.size.width-source.size.width)*scale,
source.size.height + (target.size.height-source.size.height)*scale);
}
所以现在把它们放在一起,它看起来像这样:
- (void)animateVisibleRectTo:(CGRect)frame {
CGRect source = self.scrollView.visibleRect;
CGRect target = frame;
[self.animator animateWithDuration:.5 block:^(CGFloat scale, BOOL didFinish) {
CGRect interpolatedFrame = [Interpolator interpolateRect:source to:target withScale:scale];
[self.scrollView scrollRectToVisible:interpolatedFrame animated:NO];
}];
}
这可能是一个很棒的系统,当您想要为不可动画的东西制作动画或只是对动画有更好的控制时,可以在很多系统中使用它。您可以添加stop
需要使计时器失效或显示链接并通知所有者的方法。
您需要注意的不是创建保留周期。如果一个类保留了 animator 对象,而 animator 对象保留了侦听器(类),您将创建一个保留循环。
同样作为奖励,您可以通过计算更大的开始时间来轻松实现动画的其他属性,例如延迟。您可以创建任何类型的曲线,例如缓入、缓出,通过使用适当的函数来计算currentValue
实例self.currentValue = pow(interpolation, 1.4)
将很像缓入。的幂1.0/1.4
将是相同版本的缓出。