我有一个非{nal CALayer CAShapeLayer
的{{1}}个实例。我试图使用该面具的框架来剪裁形状。哪个工作正常。但是当我更改框架时,我不希望它为框架更改设置动画。我在视图mask
中更新了相框,我发现了一些有趣的内容:
layoutSubviews
这产生的输出如下:
override func layoutSubviews() {
super.layoutSubviews()
...
if let futureMask = self.futureShape.mask {
"0.future position animation \(futureMask.animation(forKey: "position"))".print()
futureMask.removeAllAnimations()
futureMask.add(CAAnimation(), forKey: "position")
futureMask.add(CAAnimation(), forKey: "bounds")
"1.future position animation \(futureMask.animation(forKey: "position"))".print()
let nowX = computeNowX()
futureMask.frame = CGRect(x: box.left + nowX, y: box.top, width: box.width - nowX, height: box.height)
"2.future position animation \(futureMask.animation(forKey: "position"))".print()
}
}
一开始它是0.future position animations Optional(<CABasicAnimation:0x174624ac0; duration = 0.25; fillMode = backwards; timingFunction = default; keyPath = position; fromValue = NSPoint: {418.94695306710298, 14}>)
1.future position animation Optional(<CAAnimation:0x170625780; duration = 0.25>)
2.future position animation Optional(<CABasicAnimation:0x170625820; duration = 0.25; fillMode = backwards; timingFunction = default; keyPath = position; fromValue = NSPoint: {418.94695306710298, 14}>)
,指向CABasicAnimation
keyPath,持续时间为250毫秒。我把它吹走(通过position
)并添加一个存根CAAnimation,希望它什么都不做。 removeAllAnimations()
印刷品显示确实发生了这种情况。但是在我设置了1
属性后,它又恢复了原来的状态。似乎只是设置框架会重置这些动画。
如果不进行这些动画,是否无法设置框架?我希望系统中的其他动画能够继续工作。我只是想让这个特殊的遮蔽层不动画。
答案 0 :(得分:8)
最后,我发现唯一有效的方法是做到以下几点:
override func layoutSubviews() {
super.layoutSubviews()
...
if let futureMask = self.futureShape.mask {
let nowX = computeNowX()
CATransaction.setDisableActions(true)
futureMask.frame = CGRect(x: box.left + nowX, y: box.top, width: box.width - nowX, height: box.height)
CATransaction.commit()
}
}
基本上,我只是用CATransaction
调用来包装帧的设置,以禁用操作并强制提交。
已更新
remove
后,会添加两个动画(如此时打印animationKeys()
所示)。我添加了以下扩展方法来捕获模式:
extension CALayer {
func dontAnimate(_ closure:(CALayer) -> ()) {
closure(self)
self.removeAllAnimations()
}
}
这允许我编写如下代码:
self.someSubLayer.dontAnimate { layer in layer.frame = whatever }
dontAnimate
的更强大的变体可能首先对当前动画进行快照,运行closure
,然后 removeAllAnimations()
,然后恢复快照。< / p>
答案 1 :(得分:2)
只需调用图层removeAllAnimations()
之后设置框架。
class GradientView: UIView {
private(set) var gradientLayer: CAGradientLayer
override init(frame: CGRect) {
gradientLayer = CAGradientLayer()
super.init(frame: frame)
layer.insertSublayer(gradientLayer, at: 0)
}
required init?(coder aDecoder: NSCoder) {
fatalError("not implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer.frame = bounds
gradientLayer.removeAllAnimations() // remove implicit animation from frame change
}
}