iOS-CALayer
- CALayer是图层的意思。
- 每个View都有一个根图层,通过view.layer获取。
专用图层
使用专用图层可以方便地实现某些效果。
图层可以添加子图层,子图层覆盖在父图层之上
- (void)viewDidLoad {
self.view.backgroundColor =[UIColor whiteColor];
UIView *view = [[UIView alloc] initWithFrame:self.view.frame];
[self.view addSubview:view];
view.backgroundColor = [UIColor redColor];
CALayer *layer = [CALayer layer];
layer.frame = CGRectMake(200, 400, 100, 100);
layer.backgroundColor = [[UIColor blueColor] CGColor];
[view.layer addSublayer:layer];
}
效果:
图层隐式动画
- 当我们改变子图层的Animatable的属性时,系统会自动执行隐式动画。
- 当我们改变根图层的的Animatable的属性时,无隐式动画(实际上是被禁用了)。
这是一个当点击时随机改变view的颜色的示例(具有渐变效果):
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
_myView.layer.backgroundColor = [[self getRandomColor] CGColor];
_subLayer.position = [touch locationInView:self.view];
_subLayer.backgroundColor = [[self getRandomColor] CGColor];
}
- (UIColor *)getRandomColor {
NSInteger r = (int)random()%255;
NSInteger g = (int)random()%255;
NSInteger b = (int)random()%255;
NSInteger a = (int)random()%255;
return [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a/255.0f];
}
根layer的背景颜色的变化是瞬变的,无动画;子layer的背景颜色是渐变的,具有隐式动画。
判断可动画属性
方式一:在XCode中选中某个属性,在Quick Help窗口中可以看到can be animated的描述,即改变该属性会进行CA动画。
方式二:在开发者网站查表:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreAnimation_guide/AnimatableProperties/AnimatableProperties.html
禁用隐式动画
开启一个CATransaction事务,这样能保证在修改layer.frame的值之前,禁用动画的语句:setDisableActions:YES是生效的。
事务:在事务内的语句要么全都执行,要么全都不执行。
[CATransaction begin];
[CATransaction setDisableActions:YES];
///...
layer.frame = CGRectOffset(layer.frame, 100, 0);
///...
[CATransaction commit];
动画事务
参考:https://www.jianshu.com/p/90415eb764bf
CATransaction 是核心动画类,它负责成批的把多个图层树的修改作为一个原子更新到渲染树。图层的每个改变都是事务的一部分。
动画要分两部分考虑:怎么动?动多久? 即动画行为和动画时间两部分。CoreAnimation中表示行为的有CAAction协议,表示时间的有CAMediaTiming协议,当然CAAnimation都实现了这两个协议。
怎么动: 默认情况下,CALayer的可动画属性都关联到一个行为对象(实现了CAAction),即当直接修改CALayer的可动画属性时,会执行对应的行为对象。
动多久:CALayer也实现了CAMediaTiming协议,自身可以控制行为时间。在每一次Runloop中,都会创建隐式的事务(CATransaction),所有CALayer的属性修改都会包含到这个事务中去,而事务中CALayer的行为时间被默认设置为0.25s。 所以修改CALayer属性所触发的行为都会执行0.25s。
layer隐式动画实际上是自动执行了CATransaction,通过begin和commit进行入栈和出栈,并再run loop中执行一次0.25秒的隐式动画。通过CATranscation可以控制隐式动画的行为.UIView的begin-》commit动画底层也是使用CATranscation实现的。
隐式事务:当图层树被没有获得事务的线程修改的时候将会自动创建隐式事务,当线程的运行循环(run-loop)执行下次迭代的时候将会自动提交事务。
layer.alpha = 0.5;
layer.zPosition = 100;
layer.position=CGPointMake(0,0);
上述的三行代码依赖隐式事务来确保动画效果同时发生。
动画暂停和动画继续
//动画暂停
func pause(){
let interval = myLayer.convertTime(CACurrentMediaTime(), fromLayer: nil)
myLayer.timeOffset = interval
myLayer.speed = 0
}
//动画继续
func resume(){
let interval = CACurrentMediaTime() - myLayer.timeOffset
myLayer.timeOffset = 0
myLayer.beginTime = interval
myLayer.speed = 1
}
根layer没有隐式动画的原因
根layer的delegate是对应的UIView,默认的UIView的actionForLayer:forKey返回的是NSNull,所以根layer无动画;而自己创建的CALayer是没有delegate的,所以返回nil,接着调用自身的defaultActionForKey。
附:action对象的执行过程
action对象触发过程:
1.和action对象有关的事件被触发
2.创建对应的action对象
3.执行action对象
1.和action对象有关的事件被触发
触发事件包括:
layer的属性被修改。包括layer的任何属性,不仅仅只是会产生动画的部分。
layer被添加到layer阶层。标识符key是kCAOnOrder。
layer被移除layer阶层。标示符key是kCAOnOrderOut。
layer将参与transition动画。标示符key是kCATransition。(mac os)
2.创建action对象
layer调用actionForKey:方法搜索需要执行的action对象。action对象可以根据情况在不同的方法里被,具体情况如下按顺序考虑:
(因为layer搜索到一个action对象就会停止搜索。layer会根据下面顺序优先选择靠前的方法)
1.如果设置了layer的代理,可以通过执行代理方法actionForLayer:forKey:返回一个action对象。代理方法可以返回:
返回action对象,例如CAAnimation对象。
返回nil。nil表示结束actionForLayer:forKey:方法的执行,继续搜索下一个阶段。
返回[NSNull null]。表示结束搜索,即结束actionForLayer:forKey:,也结束其他阶段,将不会有隐式动画。
2.查找layer的actions属性,看key是否有对应的值。
3.查找layer的style属性。
4.layer调用defaultActionForKey:方法。
5.如果搜索到了最后阶段,layer会执行一个默认的action对象,一般是CABasicAnimation。
上面方法具体选择那种我也不知道!
3.调用action对象的runActionForLayer:object:arguments:方法执行相关操作。
如果返回的是CAAnimation实例,那么可以不实现runActionForLayer:object:arguments:方法,因为Core Animaiton已经替你做好了CAAnimation的实现。
作者:桃花流水鳜鱼肥
链接:https://www.jianshu.com/p/9e9c8ee3f7a2
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。