禁用CALayer蒙版框架更改动画

时间:2017-01-05 23:22:06

标签: ios swift3 core-animation calayer

我有一个非{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属性后,它又恢复了原来的状态。似乎只是设置框架会重置这些动画。

如果不进行这些动画,是否无法设置框架?我希望系统中的其他动画能够继续工作。我只是想让这个特殊的遮蔽层不动画。

2 个答案:

答案 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调用来包装帧的设置,以禁用操作并强制提交。

已更新

@Hlung的回答更正确。设置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
  }

}