CAShapeLayer 奇怪的动画行为

CAShapeLayer strange animation behavior

我正在尝试创建一个动画,其中两条线在用户拖动 UIView 时淡出并在用户释放拖动时淡入。
因此,我有两个函数 undrawLines(在平移手势开始时调用)和 redrawLines(在平移手势结束时调用),它们由我的 UIPanGestureRecognizer 操作处理程序调用。

func undrawLines() {

    line1.opacity = 0.0
    line2.opacity = 0.0

    line1.removeAllAnimations()
    line2.removeAllAnimations()

    let opacityLine = CABasicAnimation(keyPath: "opacity")
    opacityLine.fromValue = 1.0
    opacityLine.toValue = 0.0
    opacityLine.duration = 0.15

    line1.add(opacityLine, forKey: "disappearLine1")
    line2.add(opacityLine, forKey: "disappearLine2")

    DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: {
        mill.line1.removeFromSuperlayer()
        mill.line2.removeFromSuperlayer()
    })
}

func redrawLines() {

    line1.opacity = 1.0
    line2.opacity = 1.0

    print("redraw")
    line1.removeAllAnimations()
    line2.removeAllAnimations()

    self.layer.addSublayer(line1)
    self.layer.addSublayer(line2)

    let opacityLine = CABasicAnimation(keyPath: "opacity")
    opacityLine.fromValue = 0.0
    opacityLine.toValue = 1.0
    opacityLine.duration = 0.15

    line1.add(opacityMill, forKey: "appearLine1")
    line2.add(opacityMill, forKey: "appearLine2")
}

问题是当 redrawLines 被调用时 undrawLines 动画仍然是 运行,线条表现出奇怪的行为并且不透明度为 0。
这是一个演示,第一部分显示它应该如何,第二部分显示错误:

我认为您的问题是与完成处理程序的竞争条件:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: {
    mill.line1.removeFromSuperlayer()
    mill.line2.removeFromSuperlayer()
})

如果您的用户释放,因此 redrawLines 在 0.3 秒超时之前被调用,这仍然会被调用并删除行。

您可能想要保留一个指示当前意图的状态标志,然后在异步回调中检查它:

func undrawLines() {

    self.linesHidden = true // update state

    line1.opacity = 0.0
    line2.opacity = 0.0

    line1.removeAllAnimations()
    line2.removeAllAnimations()

    let opacityLine = CABasicAnimation(keyPath: "opacity")
    opacityLine.fromValue = 1.0
    opacityLine.toValue = 0.0
    opacityLine.duration = 0.15

    line1.add(opacityLine, forKey: "disappearLine1")
    line2.add(opacityLine, forKey: "disappearLine2")

    DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: { [weak self] in
        if self?.linesHidden == true { // check this is still what we want to do
            mill.line1.removeFromSuperlayer()
            mill.line2.removeFromSuperlayer()
        }
    })
}

func redrawLines() {

    self.linesHidden = false // update state

    line1.opacity = 1.0
    line2.opacity = 1.0

    print("redraw")
    line1.removeAllAnimations()
    line2.removeAllAnimations()

    self.layer.addSublayer(line1)
    self.layer.addSublayer(line2)

    let opacityLine = CABasicAnimation(keyPath: "opacity")
    opacityLine.fromValue = 0.0
    opacityLine.toValue = 1.0
    opacityLine.duration = 0.15

    line1.add(opacityMill, forKey: "appearLine1")
    line2.add(opacityMill, forKey: "appearLine2")
}

您显然需要将实例变量 linesHidden 添加到 class 才能使其正常工作:)