Swift动画圆形进度条

时间:2019-04-04 09:10:50

标签: swift animation progress

我已经在Swift中创建了一个圆形进度条,当用户按住视图时,它会在1.5秒内动画化为值1。但是我想在动画完成后添加一个新的viewcontroller,如果用户结束得很早,则重新启动循环进度条。有人可以帮我吗?

当用户按住视图并在放开时停止时,圆形进度条与动画一起使用。

class CounterView: UIView {
    var bgPath: UIBezierPath!
    var shapeLayer: CAShapeLayer!
    var progressLayer: CAShapeLayer!


    override init(frame: CGRect) {
        super.init(frame: frame)
        bgPath = UIBezierPath()
        self.simpleShape()
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        bgPath = UIBezierPath()
        self.simpleShape()
    }

    func simpleShape()
    {
        createCirclePath()
        shapeLayer = CAShapeLayer()
        shapeLayer.path = bgPath.cgPath
        shapeLayer.lineWidth = 5
        shapeLayer.fillColor = nil
        shapeLayer.strokeColor = UIColor.clear.cgColor

        progressLayer = CAShapeLayer()
        progressLayer.path = bgPath.cgPath
        progressLayer.lineCap = kCALineCapRound
        progressLayer.lineWidth = 5
        progressLayer.fillColor = nil
        progressLayer.strokeColor = UIColor.yellow.cgColor
        progressLayer.strokeEnd = 0.0


        self.layer.addSublayer(shapeLayer)
        self.layer.addSublayer(progressLayer)
    }

    private func createCirclePath()
    {

        let x = self.frame.width/2
        let y = self.frame.height/2
        let center = CGPoint(x: x, y: y)
        print(x,y,center)
        bgPath.addArc(withCenter: center, radius: x/CGFloat(2), startAngle: CGFloat(0), endAngle: CGFloat(6.28), clockwise: true)
        bgPath.close()
    }

    var animationCompletedCallback: ((_ isAnimationCompleted: Bool) -> Void)?

    func setProgressWithAnimation(duration: TimeInterval, value: Float)  {

        CATransaction.setCompletionBlock {
            if let callBack = self.animationCompletedCallback { callBack(true) }

        }

        CATransaction.begin()
        let  animation = CABasicAnimation (keyPath: "strokeEnd")
        animation.duration = duration
        animation.fromValue = 0
        animation.toValue = value
        animation.repeatCount = 1
        animation.timingFunction = CAMediaTimingFunction (name: kCAMediaTimingFunctionLinear)
        progressLayer.strokeEnd = CGFloat(value)
        progressLayer.add(animation, forKey: "animateprogress")

        CATransaction.commit()
}

    func removeLayers() {
        shapeLayer.removeAllAnimations()
        shapeLayer.removeFromSuperlayer()
        progressLayer.removeAllAnimations()
        progressLayer.removeFromSuperlayer()
    }





}





             class ViewController: UIViewController {


                    @IBOutlet weak var counterView: CounterView!
                    @IBOutlet weak var holdView: UIView!
                    var isAnimationCompleted = false             


                    override func viewDidLoad() {
                        super.viewDidLoad()
                        addLongPressGesture()
                       addCounterViewCallback()


                    }    
             @objc func longPress(gesture: UILongPressGestureRecognizer) {
        if gesture.state == UIGestureRecognizerState.began {
       // self.counterView.simpleShape()
        self.counterView.setProgressWithAnimation(duration: 1.5, value: 1.0)

        }
        if gesture.state == UIGestureRecognizerState.ended {
            if !isAnimationCompleted {
                self.counterView.removeLayers()
            }
        }
    }


    func addLongPressGesture(){
        let lpgr = UILongPressGestureRecognizer(target: self, action: #selector(longPress(gesture:)))
        lpgr.minimumPressDuration = 0
        self.holdView.addGestureRecognizer(lpgr)
    }

    private func addCounterViewCallback() {
        counterView.animationCompletedCallback = { [weak self] (isCompleted) in
            guard let weakSelf = self else {return}
            weakSelf.isAnimationCompleted = isCompleted
            weakSelf.addFlashView()
        }
    }


          func addFlashView(){
                        let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)

                        let resultViewController = storyBoard.instantiateViewController(withIdentifier: "ResultView") as! Flash

                        self.present(resultViewController, animated:true, completion:nil)
                    }

完成动画后添加新的viewcontroller,如果用户释放视图并再次按住它,则重新启动动画。

1 个答案:

答案 0 :(得分:0)

添加callback可以知道动画何时结束。然后使用CATransaction知道动画何时完成。

var animationCompletedCallback: (() -> Void)?
func setProgressWithAnimation(duration: TimeInterval, value: Float)  {

    CATransaction.setCompletionBlock {
        if let callBack = animationCompletedCallback {
            callBack()
        }
    }

    CATransaction.begin()


    let  animation = CABasicAnimation (keyPath: "strokeEnd")
    animation.duration = duration
    animation.fromValue = 0
    animation.toValue = value
    animation.repeatCount = .infinity
    animation.timingFunction = CAMediaTimingFunction (name: kCAMediaTimingFunctionLinear)
    progressLayer.strokeEnd = CGFloat(value)
    progressLayer.add(animation, forKey: "animateprogress")

    CATransaction.commit()
}

并在addLongPressGesture()viewDidLoad()之后添加此函数:

private func addCounterViewCallback() {
    counterView.animationCompletedCallback = { [weak self] in
        guard let weakSelf = self else {return}
        weakSelf.addFlashView()
    }
}

要删除图层,请使用此:

func removeLayers() {
   shapeLayer.removeAllAnimations()
   shapeLayer.removeFromSuperlayer()
   progressLayer.removeAllAnimations()
   progressLayer.removeFromSuperlayer()
}

更新1:

要在用户停止按动时删除动画,您需要在回调中添加这样的变量:

var animationCompletedCallback: ((isAnimationCompleted: Bool) -> Void)?

因此,CounterView中的回调将为:

if let callBack = animationCompletedCallback { callBack(true) }

在您的控制器中添加一个变量: var isAnimationCompleted = false

更改addCounterViewCallback()

private func addCounterViewCallback() {
    counterView.animationCompletedCallback = { [weak self] (isCompleted) in
        guard let weakSelf = self else {return}
        weakSelf.isAnimationCompleted = isCompleted
        weakSelf.addFlashView()
    }
}

现在,您可以在longPress()中添加一个条件:

if gesture.state == UIGestureRecognizerState.ended {
  if !isAnimationCompleted { 
      //Call remove layers code
  }
}

更新2:

CounterView中添加变量:

var isAnimationCompleted = true

像这样更改回调:

CATransaction.setCompletionBlock {
    if let callBack = self.animationCompletedCallback { callBack(isAnimationCompleted) }
}

在控制器longPress()中:

if gesture.state == UIGestureRecognizerState.ended {
   if !isAnimationCompleted {
      self.counterView.isAnimationCompleted = false
      self.counterView.removeLayers()
   }
}

addCounterViewCallback()修改为此:

private func addCounterViewCallback() {
        counterView.animationCompletedCallback = { [weak self] (isCompleted) in
        guard let weakSelf = self else {return}
        weakSelf.isAnimationCompleted = isCompleted
        if isCompleted {
          weakSelf.addFlashView()
        }
    }
}