CAAnimation为复选标记图形设置动画

时间:2016-07-13 12:33:21

标签: ios swift animation core-animation

我正在尝试制作一个简单的复选标记控件,其中只包含一个正方形和一个复选标记。我想在敲击控件时动画绘制和擦除复选标记。这就是我到目前为止所做的:

let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: checkBox.size * 2 / 3))
path.addLine(to: CGPoint(x: checkBox.size / 3, y: checkBox.size))
path.addLine(to: CGPoint(x: checkBox.size, y: 0))

pathLayer.frame = checkBox.bounds
pathLayer.path = path.cgPath
pathLayer.strokeColor = UIColor.red().cgColor
pathLayer.fillColor = nil
pathLayer.lineWidth = checkMarkWidth
pathLayer.lineJoin = kCALineJoinBevel

let pathAnimation = CABasicAnimation(keyPath:"strokeEnd")
pathAnimation.duration = checkMarkAnimationDuration
pathAnimation.fromValue = NSNumber(floatLiteral: 0)
pathAnimation.toValue = NSNumber(floatLiteral: 1)

let reverseAnimation = CABasicAnimation(keyPath:"strokeEnd")
reverseAnimation.duration = checkMarkAnimationDuration
reverseAnimation.fromValue = NSNumber(floatLiteral: 1)
reverseAnimation.toValue = NSNumber(floatLiteral: 0)
reverseAnimation.delegate = self

然后我开始这样的动画:

var on: Bool = false {
    didSet {
        if on {
            checkBox.layer.addSublayer(pathLayer)
            pathLayer.removeAllAnimations()
            pathLayer.add(pathAnimation, forKey:"strokeEnd")
        } else {
            pathLayer.removeAllAnimations()
            pathLayer.add(reverseAnimation, forKey:"strokeEnd")
        }
    }
}

最后在我的CAAnimationDelegate中我这样做:

public func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
    pathLayer.removeFromSuperlayer()
}

这看起来很不错,只是当我在真实设备上测试它时,在完成反转动画时,但在移除图层之前会有一点闪光。好像我错过了animationWillStop回调。

enter image description here

如何修复这个故障?

此外,欢迎任何其他有关如何改进此代码的建议,因为我对核心动画完全不熟悉。

1 个答案:

答案 0 :(得分:5)

核心动画有三层树,一个是模型层树,您主要与之交互。一个是表示层树,其中包含正在运行的运行动画值。最后一个是渲染层树,它实际上将层和私有渲染到核心动画。

CAAnimation仅更改CALayer的presentationLayer上的值。动画结束后,动画将被删除,strokeEnd 跳回到你的模态图层的值:1.0。这就是你有闪光灯的原因。

所以,你可以改变

var on: Bool = false {
    didSet {
        if on {
            checkBox.layer.addSublayer(pathLayer)
            pathLayer.removeAllAnimations()
            pathLayer.add(pathAnimation, forKey:"strokeEnd")
        } else {
            pathLayer.removeAllAnimations()
            pathLayer.add(reverseAnimation, forKey:"strokeEnd")
        }
    }
}

var on: Bool = false {
    didSet {
        if on {
            checkBox.layer.addSublayer(pathLayer)
            pathLayer.strokeEnd = 1.0 // set property to final state
            pathLayer.removeAllAnimations()
            pathLayer.add(pathAnimation, forKey:"strokeEnd")
        } else {
            pathLayer.strokeEnd = 0.0 // set property to final state
            pathLayer.removeAllAnimations()
            pathLayer.add(reverseAnimation, forKey:"strokeEnd")
        }
    }
}