Swift анимированный круговой индикатор выполнения - PullRequest
0 голосов
/ 04 апреля 2019

Я создал круговой индикатор выполнения в 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 голосов
/ 04 апреля 2019

Добавьте 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()
        }
    }
}
...