1、iOS动画基础回顾:UIView动画与CALayer动画的核心区别,为什么说CALayer是动画的基石
说实话,很多iOS开发者做了两三年动画,还在用UIView.animate那一套。不是说不行,但你想过没有——为什么苹果要搞一个CALayer出来?
我个人习惯,在讲动画进阶之前,先把这个底层逻辑理清楚。因为后面30章的内容,几乎每一行代码都在跟CALayer打交道。你不懂它,后面会越学越懵。
1.1 UIView动画:简单,但有限
先看一个最常见的写法:
UIView.animate(withDuration: 0.3) {
self.button.alpha = 0.0
self.button.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
}
这段代码,说白了就是让按钮淡出并缩小。简单吧?但它的本质是什么?
UIView动画其实是对CALayer动画的一层封装。你调用UIView.animate时,系统内部会帮你创建一个CABasicAnimation,然后加到对应的layer上。嗯,这里要注意——UIView动画只能操作它暴露出来的那几个属性:frame、bounds、center、transform、alpha、backgroundColor。
我在项目中遇到过一个问题:想给视图加一个圆角变化的动画,UIView.animate直接不支持。当时我还傻傻地写了个定时器去逐帧修改layer.cornerRadius……后来才知道,直接用CABasicAnimation就一行代码的事。
1.2 CALayer动画:真正的底层能力
为什么说CALayer是动画的基石?
你想想看,屏幕上所有你能看到的东西,本质上都是CALayer在渲染。UIView只是一个事件响应的壳,真正负责绘制和动画的,是它底层的layer。
直接操作CALayer,你能做什么?
- 任意属性的动画:不仅仅是UIView暴露的那几个,cornerRadius、borderWidth、shadowOffset、contents……几乎所有layer属性都能动
- 更精细的控制:动画的起始值、结束值、时间曲线、重复次数、自动反转,全由你说了算
- 组合动画:多个动画可以同时跑,也可以串行,甚至可以嵌套
- 性能优势:CALayer动画在GPU上执行,不阻塞主线程
看一个对比:
| 能力 | UIView动画 | CALayer动画 |
|---|---|---|
| 可动画属性 | 约10个 | 全部可动画属性(约50+) |
| 自定义时间曲线 | 有限(预置曲线) | 完全自定义(CAMediaTimingFunction) |
| 动画组合 | 不支持 | CAAnimationGroup |
| 逐帧控制 | 不支持 | CADisplayLink + 手动设置 |
| 3D变换 | 不支持 | CATransform3D |
我曾经接手过一个老项目,里面用UIView动画做了一个复杂的卡片翻转效果。代码写了三百多行,各种嵌套闭包,bug还一堆。我花了一个下午,全部改成CATransform3D + CAAnimationGroup,代码缩到80行,流畅度还提升了一个档次。
1.3 为什么说CALayer是动画的基石?
说白了,iOS的动画体系就是三层结构:
- UIView动画:最上层,面向业务,简单易用
- CALayer动画:中间层,面向能力,灵活强大
- Core Animation:最底层,面向渲染,负责实际绘制
UIView动画最终会落到CALayer上,CALayer动画最终会交给Core Animation去渲染。所以不管你用哪一层,底层都是CALayer在干活。
1.4 一个实战对比:圆角动画
假设你要实现一个按钮,点击后圆角从10变成30。用UIView动画怎么写?
// ❌ 这样写没用
UIView.animate(withDuration: 0.3) {
self.button.layer.cornerRadius = 30
}
你会发现圆角直接跳过去了,没有动画效果。为什么?因为UIView动画不认layer.cornerRadius这个属性。
正确的做法:
// ✅ 直接操作CALayer
let animation = CABasicAnimation(keyPath: "cornerRadius")
animation.fromValue = 10
animation.toValue = 30
animation.duration = 0.3
button.layer.add(animation, forKey: "cornerRadiusAnim")
button.layer.cornerRadius = 30 // 记得更新最终值
这里有个坑,我曾经踩过——动画结束后,layer的属性会恢复到动画开始前的值。所以一定要在动画结束后,手动把属性设置成目标值。或者用fillMode + removedOnCompletion来控制。
1.5 小结
这一章我们聊了UIView动画和CALayer动画的核心区别。说白了,UIView动画是给“懒人”用的,CALayer动画才是真正干活的。后面的课程,我们会大量使用CALayer动画来实现各种酷炫效果。
记住一句话:所有UIView动画能做的事,CALayer都能做;但CALayer能做的事,UIView动画不一定能做。
下一章,我们会深入CAAnimation的继承体系,看看这些动画类到底是怎么工作的。到时候你会明白,为什么我说“理解了CALayer,你就理解了iOS动画的一半”。