CADisplayLink 是一个能让我们和屏幕刷新率相同的频率,将内容滑到屏幕上的定时器.
CADisplayLink 的概念、属性 简述
1.CADisplayLink 是一个能让我们和屏幕刷新率相同的频率,将内容滑到屏幕上的定时器. 在应用中建立一个新的CADisplayLink 对象, 把它添加到一个 runloop 中,并给他提供一个target 和 selector 在屏幕刷新的时候调用.
2.一旦CADisplayLink 以特定的模式注册到runloop后,每当屏幕需要刷新的时候就会调用绑定的target 和selector, 这时target 可以读到CADisplayLink 的每次调用的时间戳,用来准备下一帧需要展示的数据. 在做UI更新的时候,需要通过时间戳来计算UI对象在动画的下一帧要更新的大小等。
3.在添加到runloop的时候我们应该选择高一些的优先顺序,来保证动画的平滑。可以高想一下,我们在动画的过程中,runloop如果被添加进来一些高优先顺序的任务,在执行CADisplayLink 造成动画的不流畅.
4.framelnterval 属性 (iOS10 被弃用) 是可读可写的NSInteger型值, 它是标识多少帧调用一次selector方法,默认值是1,也就是每帧都调用一次,如果每帧一次的话,也就是说,对于iOS设备而言,刷新的频率就是60HZ, 如果设置为2,那么就会每两帧调用一次,就是每秒钟刷新30次。
5.duration 属性, 只读的CFTimeInterval值, 提供每帧之间的时间,也就是屏幕每次刷新的时间。我们可以用这个时间算出下一帧要显示的UI的数值。但是 duration 只是个大概时间,如果CPU忙于其他计算,就没法保证相同频率执行屏幕绘制操作,这样的话会跳过几次调用回调方法的机会。 需要注意的是,该属性在target的selector被首次调用以后才会被赋值。selector的调用间隔时间计算方式是: 时间 = duration x frameInterval。现在设置iOS设备屏幕的FPS都是60HZ,这一点可以从CADisplayLink的duration属性看出来。duration的值都是0.166666....,即1/60 . 因为我们不能确定Apple 不会改变FPS,所以,出于安全考虑,还是先要根椐duration来判断屏幕的FPS,再去使用CADisplayLink。
6.我们通过pause属性开关控制CADisplayLink,当我们想要结束时,应该调用-(void)invalidate 从runloop 中删除并删除之前绑定的target和 selector
7.timestamp 只读的CFTimeInterval值, 表示屏幕显示的上一帧的时间戳,这个属性通常被target用来计算下一帧中应该显示的内容。它的样式像: 179699.631584;别看它这个样式很怪,与常见的unix时间戳差异很大,事实上这是CoreAnimation使用的时间格式。 每个CALayer都有一个本地时间,可以获取当前CALayer的本地时间并打印出来
CFTimeInterval localLayerTime = [myLayer convertTime:CACurrentMediaTime() fromLayer:nil];
NSLog("localLayerTime:%f",localLayerTime);
8.preferredFramesPerSecond (iOS10用这个方法) 标识每秒钟调用几次,比如每秒钟调用10次,那就是每0.1秒调用一次。
9.CADisplayLink 是不能被继承的
CADisplayLink 与 NSTimer 有什么不同
1.iOS设备的屏幕刷新频率是固定的,CADisplayLink在正常情况下会在每次刷新结束都被调用,精确定相当高。 NSTimer的精确度就显得低了点,比如 NSTimer的触发时间到的时候,这时runloop如果处在阻塞状态,触发时间就会推迟到下一个runloop周期。并且NSTimer新增了 tolerance属性,让用户可以设置可以容忍的触发的时间的延迟范围。
2.CADisplayLink使用场合相对专一,适合做UI的不停重绘,比如自定义动画引或者視頻播放的渲染。NSTimer的使用范围要广泛的多,各种需要单次或者规定时间处理的任务都可以使用。在UI相关的动画或者显示内容使用CADisplayLink比起用NSTimer的好处就是我们不需要在额外关心屏幕的刷新频率了,因为它本身就是跟屏幕刷新同步的。
CADisplayLink 使用的例子
1.用法简介
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateTextColor)];
self.displayLink.paused = YES;
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
-(void)updateTextColor{ }
- (void)startAnimation{
self.beginTime = CACurrentMediaTime();
self.displayLink.paused = NO;
}
- (void)stopAnimation{
self.displayLink.paused = YES;
[self.displayLink invalidate];
self.displayLink = nil;
}
2.给非UI对象添加动画效果
我们都知道动画效果就是一个属性的线性变化,比如UIView动画的 EasyIn EasyOut。通过数值按照不同速率的变化我们能生成更接近于真实世界的动画效果。我们也可以利用这个特性来使一些其他属性按照我们期望的曲线变化。比如当播放视频时关掉视频的声音我可以通过CADisplayLink来实现一个 EasyOut 的渐出效果;先快速的降低音量,在慢慢的渐变到静音。
注意事项:
通常来讲: iOS设备的刷新频率是60HZ,也就是每秒60次。那么每一次刷新的时间就是1/60秒 大概16.7毫秒。当我们的frameInterval值为1的时候我们需要保证的是CADisplayLink调用的 'target'的函数计算时间不应该大于16.7,否则就会出现严重的丢帧现象。
在mac应用中我们使用的不是CADisplayLink而是 CVDisplayLink它是基于C介面的用起来配置有些麻煩,但是用起来还是很简单的。
1、CPU的空闲程度
如果CPU忙于其它计算,就沒法保证以60HZ执行屏幕的绘画动作,倒致跳过若干次调用回调方法的机会,跳过次数取決CPU的忙碌程度。
2、执行回调方法所用的时间
如果执行回调時間大于重绘每帧的间隔时间,就会导致跳过若干次回调调用机会,这取決于执行时间长短。