Core Animation:基础、CALayer 和 iOS 中的动画

作者: IT Sectr 发布日期: 2026-03-01 阅读时间: 8 分钟

Core Animation 是 Apple 的低级动画框架,在 CALayer 级别工作,确保内容在 GPU 上渲染。Core Animation 是 iOS 和 macOS 中所有动画的基础:UIKit、AppKit、SceneKit 和 SpriteKit 都构建在其之上。本文解释了 CALayer、CABasicAnimation、CATransaction 的架构和实用技术。

要点

  • CALayer — Core Animation 的基础类,用于管理内容在 GPU 上的显示
  • CABasicAnimation — CALayer 单个属性从 fromValue 到 toValue 的简单动画
  • CATransaction — 将动画分组到具有共同 duration 和 completion 的一个事务中
  • CAAnimation — 抽象基类,CABasicAnimation、CAKeyframeAnimation、CAAnimationGroup 都继承自它
  • Render server — 在 GPU 上插值动画帧的独立进程(backboardd)

什么是 Core Animation?

Core Animation 是 Apple 的一个图形框架,出现在 Mac OS X 10.5 Leopard(2007)中,并从 iPhone OS(2007)的第一个版本移植到 iOS。Core Animation 管理图层(CALayer)在 GPU 上的合成、动画和渲染。iOS 中的每个 UIView 都有一个内置的 CALayer(view.layer),所有渲染都通过它进行。

Core Animation 基于隐式动画原理工作:CALayer 属性的一些更改会自动动画化(为 position、bounds、opacity、backgroundColor 等属性创建 CABasicAnimation)。隐式动画默认使用 CATransaction,持续时间为 0.25 秒,使用 easeInOut 曲线。

根据 Apple WWDC 2024 的数据,Core Animation 在配备 ProMotion 的设备上处理高达 120 FPS,使用 Metal 进行 GPU 渲染。内存中典型图层的大小为每像素 4 字节(RGBA)+ 每个图层约 100 字节的开销。建议每个屏幕不超过 1000 个图层以保持稳定的 60 FPS。

CALayer 架构

CALayer 是 Core Animation 的基础。每个 CALayer 包含位图内容(或 GPU 纹理引用)并定义几何形状(bounds、position、anchorPoint、transform、cornerRadius、borderWidth、shadow)。图层不处理触摸事件——这是 UIView/UIScrollView 的职责。图层形成层级结构(图层树),镜像视图层级。

Core Animation 支持三个图层树:模型图层树(实际属性)、呈现图层树(动画期间的当前显示)和渲染树(GPU 数据)。呈现图层用于实时读取动画的中间值。

CALayer 类型

CALayer 有专门的子类:CAShapeLayer(矢量图形)、CAGradientLayer(渐变)、CATextLayer(文本)、CATiledLayer(分割成瓦片的大图像)、CAEAGLLayer/MetalLayer(OpenGL/Metal)。CAShapeLayer 由于支持 CGPath 和 strokeStart/strokeEnd 动画,是最流行的自定义动画选择。

CABasicAnimation — 属性的基本动画

CABasicAnimation 是 CAAnimation 的子类,将 CALayer 的单个属性从初始值(fromValue)动画到最终值(toValue)或相对更改(byValue)。动画通过 layer.add(animation, forKey:) 方法添加到图层,并在渲染服务器中执行,无需应用程序在每一帧参与。

键(keyPath)是指向属性的字符串:opacity、position、bounds、transform.rotation.z、cornerRadius、shadowOpacity 等。Core Animation 支持 60 多个可动画化的 keyPath。对于自定义属性,使用 CATransaction 和呈现图层。

swift
import QuartzCore

// CABasicAnimation 用于 opacity 和 cornerRadius
func animateLayer() {
    let layer = CALayer()
    layer.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
    layer.backgroundColor = UIColor.systemBlue.cgColor
    view.layer.addSublayer(layer)

    // 1. 透明度动画
    let fadeAnim = CABasicAnimation(keyPath: "opacity")
    fadeAnim.fromValue = 1.0
    fadeAnim.toValue = 0.2
    fadeAnim.duration = 2.0
    fadeAnim.autoreverses = true
    fadeAnim.repeatCount = .infinity

    // 2. 圆角动画
    let cornerAnim = CABasicAnimation(keyPath: "cornerRadius")
    cornerAnim.fromValue = 0
    cornerAnim.toValue = 50
    cornerAnim.duration = 2.0
    cornerAnim.autoreverses = true
    cornerAnim.repeatCount = .infinity

    layer.add(fadeAnim, forKey: "fade")
    layer.add(cornerAnim, forKey: "corner")
}

// 使用 ease-in-out 的 position 动画
func moveLayer(_ layer: CALayer, to point: CGPoint) {
    let anim = CABasicAnimation(keyPath: "position")
    anim.fromValue = NSValue(cgPoint: layer.position)
    anim.toValue = NSValue(cgPoint: point)
    anim.duration = 0.6
    anim.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
    anim.isRemovedOnCompletion = false
    anim.fillMode = .forwards
    layer.add(anim, forKey: "move")
    layer.position = point // 更新模型图层
}

重要:CABasicAnimation 是临时显示(呈现图层)。动画完成后,图层返回到模型图层的初始值。要固定最终状态,请设置 isRemovedOnCompletion = false、fillMode = .forwards,并将模型图层更新为最终值。

CATransaction — 动画分组

CATransaction 是一种将 Core Animation 动画分组到单个事务中的机制。CATransaction.begin() 和 CATransaction.commit() 定义事务边界。在事务内部,可以设置公共参数:duration、timingFunction、completionBlock、disableActions。CATransaction 是 CALayer 隐式动画的基础。

隐式动画在 CALayer 属性在动画块外更改时起作用:layer.opacity = 0.5。Core Animation 使用当前 CATransaction 的 duration(默认 0.25 秒)自动创建 CABasicAnimation。要禁用隐式动画,请使用 CATransaction.setDisableActions(true)。

swift
// CATransaction — 分组和完成
func groupedAnimation() {
    CATransaction.begin()
    CATransaction.setAnimationDuration(1.5)
    CATransaction.setAnimationTimingFunction(
        CAMediaTimingFunction(name: .easeOut)
    )
    CATransaction.setCompletionBlock {
        print("All animations completed")
    }

    // 事务内的所有更改都以 1.5 的持续时间进行动画
    layer1.opacity = 0.3
    layer2.position = CGPoint(x: 200, y: 300)
    layer3.backgroundColor = UIColor.systemRed.cgColor

    CATransaction.commit()
}

// 禁用隐式动画
func updateWithoutAnimation() {
    CATransaction.begin()
    CATransaction.setDisableActions(true)
    layer.frame = newFrame // 无动画
    CATransaction.commit()
}

// CAShapeLayer 属性的动画
func animateProgress(percentage: CGFloat) {
    CATransaction.begin()
    CATransaction.setAnimationDuration(0.8)
    CATransaction.setCompletionBlock {
        print("Progress updated to (percentage)%")
    }
    progressLayer.strokeEnd = percentage / 100.0
    CATransaction.commit()
}

Swift 代码示例

Core Animation 通过 UIView 图层与 UIKit 集成。下面的示例演示了 CAShapeLayer 的动画——一个带有弧长动画和通过 CABasicAnimation 旋转图层的圆形进度条。

swift
import UIKit
import QuartzCore

class CircularProgressView: UIView {

    private let progressLayer = CAShapeLayer()

    override func layoutSubviews() {
        super.layoutSubviews()

        let path = UIBezierPath(
            arcCenter: CGPoint(x: bounds.midX, y: bounds.midY),
            radius: bounds.width / 2 - 10,
            startAngle: -.pi / 2,
            endAngle: 3 * .pi / 2,
            clockwise: true
        )

        progressLayer.path = path.cgPath
        progressLayer.strokeColor = UIColor.systemBlue.cgColor
        progressLayer.lineWidth = 8
        progressLayer.fillColor = nil
        progressLayer.strokeEnd = 0
        progressLayer.lineCap = .round
        layer.addSublayer(progressLayer)
    }

    func setProgress(_ value: CGFloat, animated: Bool = true) {
        if animated {
            CATransaction.begin()
            CATransaction.setAnimationDuration(0.6)
            CATransaction.setAnimationTimingFunction(
                CAMediaTimingFunction(name: .easeOut)
            )
            progressLayer.strokeEnd = min(max(value, 0), 1)
            CATransaction.commit()
        } else {
            progressLayer.strokeEnd = value
        }
    }
}

CAShapeLayer 将 strokeEnd 属性从 0 动画到 1,创建圆形进度条的「填充」效果。CATransaction 以 0.6 的持续时间和 easeOut 使动画流畅。layer.lineCap = .round 为线条添加圆形末端,使外观更整洁。

常见问题

Core Animation 和 UIView.animate 有什么区别?

Core Animation 在 CALayer 级别工作,通过 CABasicAnimation、CATransaction 进行管理。UIView.animate 是 Core Animation 之上的高级封装,自动为 UIView 属性创建 CABasicAnimation。Core Animation 提供更多控制:keyPath、timingFunction、fillMode、通过 CATransaction 分组。

Core Animation 中的隐式动画是什么?

隐式动画是在动画块外更改 CALayer 可动画属性时自动进行的动画。例如,layer.opacity = 0.5 创建持续时间为 0.25 秒的 CABasicAnimation。隐式动画通过 CATransaction 管理,并通过 setDisableActions(true) 禁用。

如何动画化自定义 CALayer 属性?

对于自定义属性,在 CALayer 中实现 action(forKey:) 并返回 CAAnimation。或者使用 CALayer.display() 通过 CADisplayLink 进行手动渲染和动画。对于支持 CABasicAnimation 的属性,只需将 keyPath 指定为字符串即可。

为什么 CALayer 比 UIView 更高效?

CALayer 比 UIView 更轻量:没有事件处理程序(触摸、手势),不参与 Auto Layout,不支持 accessibility。典型 CALayer 占用约 100 字节,而 UIView 占用 300 多个字节。Core Animation 在 GPU 上的渲染服务器中处理图层,不会阻塞主线程。

总结

  • Core Animation — Apple 的低级框架,用于在 GPU 上渲染 CALayer 动画
  • CALayer — 基础类,具有 60 多个可动画属性,支持 CAShapeLayer、CAGradientLayer、CATextLayer
  • CABasicAnimation — 使用 fromValue/toValue 对单个属性进行动画,通过 layer.add(animation, forKey:) 添加
  • CATransaction — 使用共同的 duration、timingFunction、completionBlock 分组动画
  • 隐式动画 — 更改 CALayer 属性时自动动画(持续时间 0.25 秒)
  • 呈现图层 — 动画期间图层的当前状态,用于读取中间值
  • 性能 — ProMotion 上高达 120 FPS,60 FPS 下最多 1000 个图层,每像素 4 字节

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读