自定义UIView动画属性

UIView提供了很多动画属性,比如frame, center, backgroundColor等,都可以产生动画效果。但有时候如果我们也想自定义一个动画属性,那应该怎么实现呢?
话不多说,直接用demo说话!

1、示例Demo

  • ProgressLayer
final class ProgressLayer: CALayer {
    @NSManaged var progress: CGFloat
    
    override init() {
        super.init()
    }
    override init(layer: Any) {
        super.init(layer: layer)
        if let presentationLayer = layer as? ProgressLayer {
            progress = presentationLayer.progress
        }
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    override class func needsDisplay(forKey key: String) -> Bool {
        if key == "progress" { return true }
        return super.needsDisplay(forKey: key)
    }
    override func action(forKey event: String) -> CAAction? {
        if event == "progress" {
            if let animation = super.action(forKey: "backgroundColor") as? CABasicAnimation {
                animation.keyPath = event
                if let pLayer = presentation() {
                    animation.fromValue = pLayer.progress
                }
                animation.isRemovedOnCompletion = true
                animation.fillMode = .forwards
                animation.toValue = nil
                return animation
            }
            setNeedsDisplay()
            return nil
        }
        return super.action(forKey: event)
    }
    
    
    override func draw(in ctx: CGContext) {
        super.draw(in: ctx)
        var frame = self.bounds
        frame.size.width *= progress
        ctx.setFillColor(UIColor.red.cgColor)
        ctx.fill(frame)
    }
}
  • ProgressView
final class ProgressView: UIView {
    override class var layerClass: Swift.AnyClass { return ProgressLayer.self }
    
    var progressLayer: ProgressLayer { return layer as! ProgressLayer }
    
    @objc dynamic var progress: CGFloat {
        get { return progressLayer.progress }
        set { progressLayer.progress = min(1, max(0, newValue)) }
    }
}
    @IBAction func resetPressed(_ sender: Any) {
        progressView.progress = 0
        slider.setValue(0, animated: false)
    }
    
    @IBAction func loadPressed(_ sender: Any) {
        UIView.animate(withDuration: 2) {
            self.progressView.progress = 1
        }
    }
    
    @IBAction func sliderValueChanged(_ sender: Any) {
        progressView.progress = CGFloat(slider.value)
    }
CustomAnimatableProperty.gif

参考资料

  • Custom Property UIView Block Animation

你可能感兴趣的:(自定义UIView动画属性)