Skip to content

01 - iOS 动画全栈

目录

  1. 动画体系概览
  2. Core Animation 架构
  3. UIView 动画
  4. CAAnimation 核心
  5. CATransaction
  6. CADisplayLink
  7. UIViewPropertyAnimator
  8. 核心动画层级
  9. 动画性能优化
  10. 动画与 Android 对比
  11. 面试考点汇总

1. 动画体系概览

1.1 iOS 动画层级

iOS 动画体系:

┌────────────────────────────────────────────┐
│           UIView Animation                  │  ← 高级 API
│  (最易用, 最常用)                          │
├───────────────────────────────────────────┤
│         CAAnimation Subclasses              │  ← 中层 API
│  (CAKeyframeAnimation/CABasicAnimation)    │
├───────────────────────────────────────────┤
│           CATransaction                     │  ← 事务管理
│  (动画事务/提交机制)                        │
├───────────────────────────────────────────┤
│      CADisplayLink / CAAction               │  ← 底层
│  (屏幕刷新回调/图层动画)                    │
├───────────────────────────────────────────┤
│      Core Graphics / Metal                  │  ← 最底层
│  (自定义渲染)                               │
└───────────────────────────────────────────┘

1.2 动画 API 选型指南

场景推荐 API复杂度
简单属性变化UIView.animate
弹性/阻尼效果UIViewPropertyAnimator⭐⭐
关键帧动画CAKeyframeAnimation⭐⭐
自定义路径CAKeyframeAnimation + UIBezierPath⭐⭐⭐
物理模拟UIDynamicAnimator⭐⭐⭐
逐帧控制CADisplayLink + 手动更新⭐⭐⭐⭐
3D/高性能Metal + CAEAGLLayer⭐⭐⭐⭐⭐

2. Core Animation 架构

2.1 渲染管线

Core Animation 渲染管线:

┌─────────────┐    ┌──────────────┐    ┌──────────────┐
│  CPU 线程    │    │  Display     │    │  GPU 线程     │
│  (Main Thread)│    │  Server       │    │  (Display    │
├──────────────┤    ├──────────────┤    │  Thread)     │
│              │    │              │    │              │
│ 1. 创建动画   │───→│ 2. 生成    │───→│ 3. 合成      │
│    CAAction   │    │    Render   │    │    CAContext │
│              │    │    Context    │    │              │
│ 4. 提交       │    │ 5. 提交到    │    │ 6. 刷新      │
│    CATransaction│  │    CGLayer   │    │    CADisplay │
│              │    │              │    │    Link       │
└──────────────┘    └──────────────┘    └──────────────┘

渲染线程:
• Main Thread: CA 图层树修改、动画创建
• CA Server Thread: 图层合成、变换计算
• GPU Thread: 像素渲染、屏幕刷新

2.2 CALayer 层级结构

CALayer 树结构:

rootLayer (UIView.layer)
├── layer1 (子视图层)
│   ├── layer1.1
│   └── layer1.2
├── layer2
│   ├── layer2.1
│   └── layer2.2
│       └── layer2.2.1
└── layer3

图层属性:
├── 变换: transform (CATransform3D)
├── 内容: contents (CGImage)
├── 背景: backgroundColor (CGColor)
├── 阴影: shadowColor/shadowOpacity/shadowPath
├── 圆角: cornerRadius
├── 边框: borderColor/borderWidth
├── 蒙版: masksToBounds/mask
├── 裁剪: cornerCurve
├── 渲染: drawsAsynchronously
└── 内容缩放: contentsScale (Retina 适配)

3. UIKit 动画

3.1 UIView.animate

swift
// 基础动画
UIView.animate(withDuration: 0.3) {
    self.view.alpha = 0.5
    self.view.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
} completion: { finished in
    print("动画完成")
}

// 带延迟/选项
UIView.animate(withDuration: 0.5,
               delay: 0.2,
               options: [.curveEaseInOut, .allowUserInteraction],
               animations: {
    self.view.frame.origin.x += 100
}, completion: nil)

// 关键选项
// .curveEaseInOut: 缓入缓出
// .curveEaseOut: 缓出
// .curveEaseIn: 缓入
// .curveLinear: 线性
// .allowUserInteraction: 动画期间允许交互
// .beginFromCurrentState: 从当前状态开始
// .autoreverse: 动画后自动回退

3.2 Spring 弹性动画

swift
UIView.animate(withDuration: 0.4,
               delay: 0,
               usingSpringWithDamping: 0.6,  // 0-1,值越小弹跳越大
               initialSpringVelocity: 1.0,   // 初始速度
               options: .curveEaseOut,
               animations: {
    self.view.transform = .identity
}, completion: nil)

3.3 动画组

swift
UIView.animate(withDuration: 0.3,
               animations: {
    self.view.alpha = 0
    self.view.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
}, completion: { _ in
    UIView.animate(withDuration: 0.3, animations: {
        self.view.alpha = 1
        self.view.transform = .identity
    })
})

4. CAAnimation 核心

4.1 CAAnimation 体系

CAAnimation 体系:

CAAnimation (基类)
├── CABasicAnimation       // 基础动画 (单属性)
├── CAKeyframeAnimation    // 关键帧动画 (多值)
├── CAGroupAnimation       // 动画组 (组合)
└── CATransition           // 转场动画

4.2 CABasicAnimation

swift
let animation = CABasicAnimation(keyPath: "position")
animation.fromValue = NSValue(cgPoint: CGPoint(x: 0, y: 0))
animation.toValue = NSValue(cgPoint: CGPoint(x: 100, y: 100))
animation.duration = 0.5
animation.fillMode = .forwards
animation.isRemovedOnCompletion = false
animation.delegate = self

layer.add(animation, forKey: "move")

// 常用 keyPath:
// "position" - 位置
// "bounds.size" - 大小
// "opacity" - 透明度
// "transform.rotation.z" - 旋转
// "cornerRadius" - 圆角
// "shadowOpacity" - 阴影
// "contents.rect" - 内容缩放

4.3 CAKeyframeAnimation

swift
let keyframeAnim = CAKeyframeAnimation(keyPath: "position")

// 路径动画
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addQuadCurve(to: CGPoint(x: 300, y: 200),
                  controlPoint: CGPoint(x: 150, y: -50))
keyframeAnim.path = path.cgPath
keyframeAnim.duration = 2.0
keyframeAnim.calculationMode = .cubic  // 平滑插值
keyframeAnim.rotationMode = .rotateAuto  // 沿路径方向旋转

layer.add(keyframeAnim, forKey: "followPath")

// 常用 calculationMode:
// .linear: 线性插值
// .cubic: 平滑插值
// .discrete: 离散跳变
// .cubicPaced: 均匀速度平滑

4.4 CAAnimationDelegate

swift
class AnimationDelegate: NSObject, CAAnimationDelegate {
    func animationDidStart(_ anim: CAAnimation) {
        print("动画开始")
    }
    
    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        if flag {
            print("动画完成")
            layer.position = CGPoint(x: 100, y: 100) // 固定最终位置
        }
    }
}

5. CATransaction

5.1 事务机制

CATransaction 机制:

┌─────────────────────────────────────────────┐
│              CATransaction                   │
├───────────┬───────────────┬────────────────┤
│  begin()  │   commit()    │   flush()      │
│  开启事务  │   提交事务     │   立即刷新     │
├───────────┼───────────────┼────────────────┤
│  setValue:│  批量提交所有  │  不等 runloop  │
│  forKey:  │  动画变更      │   就刷新       │
│ (动画属性) │              │                │
└───────────┴───────────────┴────────────────┘

// 自动事务(大多数动画场景)
UIView.animate { ... }  // 内部自动创建/提交事务

// 手动事务(需要精细控制)
CATransaction.begin()
CATransaction.setAnimationDuration(0.5)
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: .easeOut))
layer.opacity = 0
layer.position = CGPoint(x: 100, y: 100)
CATransaction.commit()

5.2 隐式动画

隐式动画(Implicit Animation):

当修改 CALayer 的可动画属性时,自动创建 CABasicAnimation

可自动动画的属性:
├── bounds
├── position
├── opacity
├── backgroundColor
├── cornerRadius
├── transform
├── shadowColor/shadowOpacity/shadowRadius
└── contentsRect

关闭隐式动画:
CATransaction.disableActions()
layer.opacity = 0  // 立即生效,无动画

或单独关闭:
layer.actions = ["opacity": NSNull()]

swift
// 逐帧精确控制
class FrameAnimator {
    private var displayLink: CADisplayLink?
    private var startTime: CFTimeInterval = 0
    
    func startAnimating() {
        displayLink = CADisplayLink(target: self, selector: #selector(updateFrame))
        displayLink?.add(to: .main, forMode: .common)
    }
    
    @objc func updateFrame(displayLink: CADisplayLink) {
        let elapsed = displayLink.timestamp - startTime
        // 根据时间计算动画状态
        let progress = CGFloat(elapsed / 2.0)  // 2秒动画
        self.view.alpha = 1.0 - progress
        self.view.transform = CGAffineTransform(scaleX: 1-progress, y: 1-progress)
    }
    
    func stopAnimating() {
        displayLink?.invalidate()
        displayLink = nil
    }
}

CADisplayLink 特点:
 与屏幕刷新率同步(60/120Hz
 在主线程运行
 提供精确的时间戳
 适合逐帧动画/物理模拟
 不消耗 CPU(无刷新时休眠)

7. UIViewPropertyAnimator

7.1 交互式动画

swift
// UIViewPropertyAnimator 是 iOS 10+ 推荐的动画 API
let animator = UIViewPropertyAnimator(duration: 1.0,
                                      curve: .easeInOut,
                                      animations: {
    self.view.alpha = 0
    self.view.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
})

animator.addAnimations({
    self.view.transform = .identity
}, delayFactor: 0.2)

// 交互式控制
animator.startAnimation()

// 可中途修改
animator.pauseAnimation()  // 暂停
animator.continueAnimation(withTimingParameters: nil,
                           intersectionDuration: 0.5)  // 继续
animator.stopAnimation(false)  // 停止(保持当前位置)

// 弹簧动画
let springParams = UISpringTimingParameters(mass: 1,
                                             stiffness: 1000,
                                             damping: 300,
                                             initialVelocity: CMVector3D())
let springAnimator = UIViewPropertyAnimator(duration: 0,
                                            timingParameters: springParams,
                                            animations: { ... })

8. 核心动画层级

8.1 CATransition

swift
// 页面转场效果
let transition = CATransition()
transition.duration = 0.3
transition.type = .push  // .reveal/.fade/.moveIn/.cube/.suckEffect/.oglFlip
transition.subtype = .fromRight
transition.delegate = self
view.layer.add(transition, forKey: kCATransition)

8.2 UIDynamicAnimator(物理模拟)

swift
class PhysicsAnimator {
    private let dynamicAnimator = UIDynamicAnimator()
    private let gravity = UIGravityBehavior()
    private let collision = UICollisionBehavior()
    private let snap = UISnapBehavior()
    
    func addGravity() {
        dynamicAnimator.addBehavior(gravity)
    }
    
    func addCollision(with views: [UIView]) {
        collision.addBoundary(withIdentifier: "floor" as NSCopying,
                             from: CGPoint(x: 0, y: screenBounds.height),
                             to: CGPoint(x: screenBounds.width, y: screenBounds.height))
        for view in views {
            collision.addItem(view)
        }
        dynamicAnimator.addBehavior(collision)
    }
    
    func snapTo(view: UIView, point: CGPoint) {
        snap = UISnapBehavior(item: view, snapPoint: point)
        snap.damping = 0.5
        dynamicAnimator.addBehavior(snap)
    }
}

9. 动画性能优化

9.1 可动画属性分类

CALayer 属性性能分类:

┌──────────────────┬──────────────────┬─────────────────┐
│ 图层(快速)      │ 内容(中等)      │ 其他(慢速)     │
├──────────────────┼──────────────────┼─────────────────┤
│ backgroundColor  │ transform        │ shadowPath      │
│ cornerRadius     │ opacity          │ mask            │
│ bounds           │ contentStretch   │ contentsGravity │
│ hidden           │                  │                 │
│ contentsGravity  │                  │                 │
│ masksToBounds    │                  │                 │
└──────────────────┴──────────────────┴─────────────────┘

优化原则:
• 优先使用图层属性动画(无需重绘内容)
• transform 是 GPU 加速的
• shadowPath 缓存阴影,避免实时计算

9.2 常见优化手段

优化手段说明效果
使用 transformGPU 加速⭐⭐⭐
预计算 shadowPath避免实时计算⭐⭐⭐
合并图层减少绘制次数⭐⭐
rasterizationScale = 0关闭栅格化⭐⭐
减少隐式动画用显式动画控制⭐⭐
CADisplayLink逐帧精确控制⭐⭐
避免离屏渲染少用 masksToBounds⭐⭐⭐

10. 动画与 Android 对比

概念iOSAndroid/Kotlin
基本动画UIView.animateObjectAnimator
关键帧CAKeyframeAnimationValueAnimator/PropertyAnimator
弹簧动画UIViewPropertyAnimatorSpringAnimation (MotionLayout)
属性动画CALayer + CAAnimationPropertyAnimation
转场CATransitionActivityOptions
物理模拟UIDynamicAnimatorPhysics2D
逐帧CADisplayLinkChoreographer
动画监听CAAnimationDelegateAnimatorListener/AnimatorUpdateListener
自定义动画Core Graphics/MetalCanvas/OpenGL/Vulkan

11. 面试考点汇总

高频面试题

  1. Core Animation 的渲染线程和主线程的关系?

    • 主线程修改图层 → CA 服务线程合成 → GPU 渲染
    • 动画创建在 CPU,合成在 GPU
    • runloop 中 commit 动画
  2. 隐式动画和显式动画的区别?

    • 隐式:修改 CALayer 属性自动触发动画
    • 显式:手动创建 CAAnimation
    • 关闭隐式:CATransaction.disableActions()
  3. 如何优化动画性能?

    • 使用 transform(GPU 加速)
    • 预计算 shadowPath
    • 合并图层减少绘制
    • 避免离屏渲染
  4. CADisplayLink 的用途?

    • 逐帧精确控制动画
    • 与屏幕刷新率同步
    • 适合物理模拟和自定义渲染
  5. UIView.animate 和 UIViewPropertyAnimator 的区别?

    • UIView.animate:一次性、不可暂停
    • UIViewPropertyAnimator:可暂停/恢复/交互、iOS 10+ 推荐

面试回答模板

"iOS 动画分四层:UIView 动画(最常用)、CAAnimation 中层 API、CATransaction 事务管理、CADisplayLink 逐帧控制。渲染管线是 CPU 创建动画 → CA Server 合成 → GPU 渲染。性能优化关键是 transform 用 GPU、shadowPath 缓存、减少离屏渲染。"


本文档对标 Android 12_Animation/ 的深度