iOS-CALayer

本文详细探讨了iOS中的CALayer,包括专用图层、图层的子图层管理、图层隐式动画的原理与控制,以及如何判断和禁用隐式动画。通过示例展示了根layer和子layer在动画表现上的差异,并介绍了CATransaction在动画事务中的作用。最后,文章解释了动画暂停、继续以及action对象的执行流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值