使用curveEaseOut对UIView子类进行动画处理

时间:2019-02-21 00:45:33

标签: ios swift uiviewanimation

我有一个自定义绘制的进度条,与过渡选项相比,我希望以更流畅的方式进行动画处理。但是它没有像我在下面那样对.curveEaseOut做出响应。如果将其更改为.transitionCrossDissolve,则可以使用,但是我希望使用曲线动画。我该如何使用它?

@IBOutlet var experienceProgress: experienceBar!

func updateProgress() {
    experienceProgress.progress = 0.5

    experienceProgress.setNeedsDisplay()

    UIView.transition(with: experienceProgress, 
                      duration: 1.25, 
                      options: UIView.AnimationOptions.curveEaseOut, 
                      animations: {
        self.experienceProgress.layer.displayIfNeeded()
    })
}

@IBDesignable
class experienceBar: UIView {

    var progress:CGFloat = 0

    override func draw(_ rect: CGRect) {
        let color = UIColor(red: 220/255, green: 0, blue: 80/255, alpha: 1.000)

        let rectanglePath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: progress * 132, height: 8.5))
        color.setFill()
        rectanglePath.fill()
    }
}

1 个答案:

答案 0 :(得分:3)

根本的问题是您的draw(_:)是给定时间视图的快照,因此不容易创建动画。要为UIView对象设置动画,最简单的方法就是使用可设置动画的属性。作为UIView documentation says

  

可以对多个视图属性进行更改,使它们具有动画效果-即,更改属性会创建一个从当前值开始并以您指定的新值结束的动画。 UIView类的以下属性是可动画的:

     
      
  • frame
  •   
  • bounds
  •   
  • center
  •   
  • transform
  •   
  • alpha
  •   
  • backgroundColor
  •   

从技术上讲,从理论上讲您可以做自己的手动动画,但是通常最好首先查看是否可以重构代码以使用以下UIView个可动画属性之一。

幸运的是,在这种情况下,您可以消除draw(_:)并将其替换为使用子视图的东西,您可以在其中对子视图的frame(这是可动画的属性)进行动画处理,以反映“百分比完成”部分。

@IBDesignable
public class CustomProgressView: UIView {
    public var progress: CGFloat = 0 { didSet { updateProgress() } }

    private var progressView: UIView = {
        let progressView = UIView()
        progressView.backgroundColor = UIColor(red: 220/255, green: 0, blue: 80/255, alpha: 1)
        return progressView
    }()

    override public init(frame: CGRect = .zero) {
        super.init(frame: frame)
        configure()
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        configure()
    }

    override public func layoutSubviews() {
        super.layoutSubviews()
        updateProgress()
    }

    override public func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        progress = 0.5
    }
}

private extension CustomProgressView {
    func configure() {
        addSubview(progressView)
    }

    func updateProgress() {
        var rect = bounds
        rect.size.width *= progress

        progressView.frame = rect
    }
}

然后您可以做:

UIView.animate(withDuration: 1, delay: 0, options: .curveEaseOut, animations: {
    self.progressView.progress = 0.75
}, completion: nil)

一些不相关的观察结果

  1. 我不太了解progress * 132的意图。因此,我只是假设progress是介于0.0和1.0之间的百分比,并且子视图会越过该百分比。

  2. 我在didSet属性的progress中自动进行了子视图的更新。视图控制器(或其他控制器)永远不必手动说setNeedsDisplay或类似的东西。

  3. 我将类名更改为以大写字母开头。变量和方法名称以小写字母开头,但类型名称(如类,结构,枚举等)始终以大写字母开头。

  4. 我注意到您做了这个@IBDesignable。如果是这样,通常最好将prepareForInterfaceBuilder的值设置为有趣的值,以便您可以在IB中更好地查看进度视图。