Core Animation
问题
Core Animation 的核心概念和常用动画 API?
答案
CALayer 与 UIView
| UIView | CALayer | |
|---|---|---|
| 框架 | UIKit | QuartzCore |
| 响应事件 | ✅ | ❌ |
| 动画 | UIView.animate | CAAnimation |
| 关系 | 每个 UIView 持有一个 layer |
隐式动画
独立创建的 CALayer 修改属性会自动产生 0.25s 动画:
let layer = CALayer()
layer.backgroundColor = UIColor.red.cgColor
view.layer.addSublayer(layer)
// 以下修改自动有动画
layer.position = CGPoint(x: 200, y: 200)
layer.opacity = 0.5
信息
UIView 的 backing layer 默认禁用隐式动画(在 actionForLayer 中返回 NSNull)。需要用 UIView.animate 包裹才有动画效果。
显式动画
// CABasicAnimation
let anim = CABasicAnimation(keyPath: "position.x")
anim.fromValue = 0
anim.toValue = 300
anim.duration = 1.0
anim.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
layer.add(anim, forKey: "moveX")
// CAKeyframeAnimation(关键帧)
let keyframe = CAKeyframeAnimation(keyPath: "position")
keyframe.values = [
CGPoint(x: 0, y: 0),
CGPoint(x: 100, y: -50),
CGPoint(x: 200, y: 0)
].map { NSValue(cgPoint: $0) }
keyframe.duration = 2.0
layer.add(keyframe, forKey: "path")
// CAAnimationGroup(组合动画)
let group = CAAnimationGroup()
group.animations = [moveAnim, scaleAnim, fadeAnim]
group.duration = 1.5
layer.add(group, forKey: "group")
UIView.animate
UIView.animate(withDuration: 0.3, delay: 0, options: .curveEaseOut) {
view.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
view.alpha = 0.5
} completion: { _ in
view.transform = .identity
view.alpha = 1.0
}
// Spring 弹性动画
UIView.animate(withDuration: 0.5, delay: 0,
usingSpringWithDamping: 0.6,
initialSpringVelocity: 0.5) {
view.center = newCenter
}
常见面试问题
Q1: 动画结束后 layer 回到原位怎么解决?
答案:CA 动画默认操作的是 presentationLayer(视觉效果),不修改 modelLayer(真实属性)。需要:
- 设置
anim.fillMode = .forwards+anim.isRemovedOnCompletion = false(不推荐,实际属性未变) - 或在添加动画前/后手动设置 layer 属性为目标值(推荐)
Q2: CADisplayLink 是什么?
答案:一个与屏幕刷新同步的定时器,每帧回调一次(60fps = 每 16.67ms)。适合做帧动画、自定义动画引擎。比 Timer 更精准。