连续执行CGAffineTransform缩放动画导致视图异常变大
iOS视图缩放动画快速切换时尺寸异常变大的成因
问题场景
在iOS开发中,快速触发视图在CGAffineTransform(scaleX: 1, y: 1)与CGAffineTransform(scaleX: 0.2, y: 0.2)之间的缩放动画时,会出现视图尺寸超出预期变大的问题,演示效果如下:

示例代码:
import UIKit class ViewController: UIViewController { let greenView = UIView() var isTransformed = false override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white view.addSubview(greenView) greenView.frame = CGRect(x: view.frame.midX-50, y: 150, width: 100, height: 100) greenView.backgroundColor = .green let transformButton = UIButton() transformButton.setTitle("Transform", for: .normal) transformButton.frame = CGRect(x: view.frame.midX-50, y: 275, width: 100, height: 40) transformButton.setTitleColor(.systemBlue, for: .normal) transformButton.addTarget(self, action: #selector(didTapTransform), for: .touchUpInside) view.addSubview(transformButton) } @objc func didTapTransform() { if isTransformed { UIView.animate(withDuration: 2) { var t = CGAffineTransform(scaleX: 1, y: 1) self.greenView.transform = t } } else { UIView.animate(withDuration: 2) { var t = CGAffineTransform(scaleX: 0.2, y: 0.2) self.greenView.transform = t } } print(greenView.transform) isTransformed = !isTransformed } }
问题成因
核心原因是UIKit动画的实时插值特性与未完成动画的状态叠加:
- UIKit的
UIView.animate动画是基于视图的当前状态进行插值计算的。当动画正在执行时,视图的transform属性并不是设置的目标值,而是处于动画过程中的中间过渡值(比如从1缩放到0.2的过程中,可能是0.7、0.5等动态变化的值)。 - 当快速点击按钮触发反向动画时,代码直接给视图设置新的目标
transform,UIKit会把当前动画的中间过渡值作为新动画的起始值,而不是我们预期的scale=1或scale=0.2。 - 反复快速切换动画时,每次新动画的起始点都是上一次未完成动画的中间状态,相当于多次基于动态中间值做缩放动画的叠加,最终导致视图的
transform偏离预期的1或0.2,出现尺寸异常变大的情况。
举个具体例子:第一次动画从1缩放到0.2,执行到一半时transform是0.6,此时触发反向动画到1,UIKit会从0.6动画到1;如果此时再次快速切换,视图的transform可能处于0.8,又会从0.8动画到0.2,多次循环后,实际的缩放值会不断偏离初始基准值,最终出现尺寸异常。
另外,代码中直接使用CGAffineTransform(scaleX:...)是创建新的缩放变换,而非基于当前变换做修改,但由于动画未完成时的动态状态,导致新动画的起始点错误,累积后出现问题。
内容的提问来源于stack exchange,提问作者Peter Tao
相关产品推荐
相关产品推荐

