乐于分享
好东西不私藏

iOS 动画 -CATransaction CATransition UIView.transition

iOS 动画 -CATransaction CATransition UIView.transition

首先看下CATransaction,它很好理解,并且也是另外两个的基础。
// CATransaction 的典型使用CATransaction.begin()CATransaction.setAnimationDuration(0.5)CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: .easeOut))CATransaction.setCompletionBlock {    print("动画完成")}layer.position = CGPoint(x: 300, y: 400)  // 这会变成动画layer.opacity = 0.5                        // 这也是动画CATransaction.commit()  // 批量提交,同时执行
CATransaction 是 Core Animation 的事务机制,它不是一个动画类型,而是一个批量提交动画更改的容器
  1. 你对 CALayer 属性的修改(position、opacity、transform 等)

  2. 这些修改不会立即生效,而是被收集到当前事务中

  3. 当当前 RunLoop 周期结束时(或手动 commit()),事务被提交

  4. Core Animation 计算所有变化之间的插值,生成动画

CATransition负责视图层级切换的过渡效果

CATransaction和CATransition的前缀都是来自core animation,QuartzCore框架。

UIView.transition 是对 CATransition 的便捷封装,下面用代码说明CATransition和UIView.transition以及CATransaction之间的关系
// 你写的代码UIView.transition(with: myView,                   duration: 0.5,                  options: [.transitionFlipFromLeft]) {    // 视图状态改变    myView.backgroundColor = .red    myView.subview.isHidden = true}// 底层等效实现(简化版)CATransaction.begin()CATransaction.setAnimationDuration(0.5)// 创建转场动画并添加到 layerlet transition = CATransition()transition.type = .pushtransition.subtype = .fromLeftmyView.layer.add(transition, forKey: "transition")// 执行视图修改(会被 CATransaction 捕获)// 注意:UIView 的 backgroundColor 修改会转换为 CALayer 的动画CATransaction.setCompletionBlock {    // UIView.transition 的 completion}CATransaction.commit()
最后看下CATransaction的嵌套
示例代码运行表现为,redLayer 和 greenLayer 同时向右移动100,blue也同这两个layer一起开始运动,只是blue很快结束(只0.5s)
 1. 每次调用CATransaction.begin()都会创建一个新的事务,并将其推入事务栈(成为当前事务)。
2. 内层事务可以重新设置某些属性(如动画时长、动画曲线、禁用动画标志等),这些设置仅在内层事务范围内有效。
3. 当内层事务提交(commit)时,它只是从栈中弹出,并不会立即提交到渲染服务。只有最外层事务提交时,整个事务(包括所有嵌套事务)才会被一起提交。
4. 内层事务中修改的设置,在离开内层事务后(回到外层事务),外层事务的设置会恢复。

 Core Animation 的更新并不是“你每改一行代码就立刻发给 GPU/渲染进程”,而是批量收集

在事务打开期间,你对 layer 的属性修改会被记录成“待提交的变更”
只有事务栈深度回到 0(最外层 commit),才意味着“这一批变更收集完了”

因此内层 commit 的作用是:

  • 结束内层的配置范围(比如内层设置 setDisableActions(true) 只影响内层)
  • 但不触发整批变更的最终提交
虽然关于CATransaction讲了这么多,但是不得不单独提一下我们最常它来禁用隐式动画
CATransaction.begin()CATransaction.setDisableActions(true)layer.position = CGPoint(x: 50, y: 50)   // 不动画(受内层影响)CATransaction.commit()