Core Animation
Core Animation 是 iOS 的 UIView 的基础和底层,属于 UIKit;在 macOS 上也有对应的封装 NSView,属于 AppKit。
CALayer
CALayer 类在概念上和 UIView 类似,同样也是一些被层级关系树管理的矩形块;实际上 UIView 背后关联的图层,才是真正在屏幕上显示的,它们很多的属性也是相对应的。和 UIView 最大的不同是,CALayer 不处理用户的交互。
为什么 iOS 要基于 UIView 和 CALayer 提供两个平行的层级关系呢?原因在于要做职责分离。在 iOS 和 macOS 两个平台上,事件和用户交互有很多地方的不同,基于 多点触控的用户界面和基于鼠标键盘的有着本质的区别,它们共享 Core Animation 对图形的绘制,并分别实现用户交互的各种接口。
既然有了简洁的 UIView 的高级接口,为什么还要了解 Core Animation 呢?虽然这个框架的名字叫做 Core Animation,实际上很多丰富的、自定义的视觉效果,我们要通过 CALayer 才能实现,而这些是 UIView 没有暴露出来的,包括:
- 阴影、圆角、边框
- 3D 变换
- 非矩形范围
- 透明遮罩
- 多级非线性动画
- 粒子效果 (CAEmitterLayer)
- 渐变效果 (CAGradientLayer)
CALayer 有三个视觉元素,中间的 contents 属性是这样声明的:var contents: AnyObject?
,实际上它必须是一个 CGImage 才能显示。
隐式动画
你并不需要在 Core Animation 中手动打开动画,任何对 CALayer 属性的改变都不是瞬间完成的,而是从先前的值平滑地过渡到新的值,除非你明确禁用了这个功能,这是框架默认的“隐式动画”。
在这个示例中我们仅仅是改变了 CALayer 的一个属性,并没有指定任何动画的类型,而 Core Animation 自动帮我们实现了一个平滑的动画效果。
import UIKit
class ViewController: UIViewController {
private let colorLayer = CALayer()
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
colorLayer.frame = CGRect(origin: CGPoint.zero, size: CGSize(width: 100, height: 100))
colorLayer.backgroundColor = UIColor.blue.cgColor
self.view.layer.addSublayer(colorLayer)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// randomize the layer background color
let red = CGFloat(arc4random()) / CGFloat(UInt32.max)
let green = CGFloat(arc4random()) / CGFloat(UInt32.max)
let blue = CGFloat(arc4random()) / CGFloat(UInt32.max)
colorLayer.backgroundColor = UIColor(red: red, green: green, blue: blue, alpha: 1.0).cgColor
}
}
Core Animation 在每个 RunLoop 周期中自动开始一次新的事务(RunLoop 是 iOS 负责收集用户输入,处理未完成的定时器或者网络事件,最终重新绘制屏幕的东西),即使你不显式地使用 [CATransaction begin]