1

I'm trying to create my custom activity indicator thing, this is what I have so far:

override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .white

        let center = view.center
        let circularPath = UIBezierPath(arcCenter: center, radius: 180, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)
        shapeLayer.path = circularPath.cgPath

        shapeLayer.strokeColor = UIColor.green.cgColor
        shapeLayer.lineWidth = 20
        shapeLayer.lineCap = CAShapeLayerLineCap.round
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.strokeEnd = 0


        view.layer.addSublayer(shapeLayer)

        UIView.animate(withDuration: 10, delay: 0, options: [], animations: {
            let basicAnimation = CABasicAnimation(keyPath: "strokeEnd")

            basicAnimation.toValue = 1
            basicAnimation.duration = 2

            basicAnimation.fillMode = CAMediaTimingFillMode.forwards
            basicAnimation.isRemovedOnCompletion = false
            self.shapeLayer.add(basicAnimation, forKey: "key")
        }) { (finished) in
            if finished {
                self.shapeLayer.removeFromSuperlayer()
            }
        }





    }

So, after the animation is completed, I will present a new controller or something. The issue is that the completion is being called immediately. So, how I can wait for

kytawy
  • 13
  • 3

2 Answers2

0

You can add a delayed dispatcher with the delay exactly equal duration:

DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
    // The job has to be done after animation
}

Alternatively you may use CATransaction.setCompletionBlock, but it needs some deeper knowledge about the CA itself and you may want to use the first option.

Mojtaba Hosseini
  • 95,414
  • 31
  • 268
  • 278
0

UIView.animate() and CABasicAnimation are two different things. The completion is being called right away because the UIView.animate() method does not know what is happening with the other. It sees no standard UIView animations and so fires the completion block.

One way to achieve this is to use an animationDidStop delegate method. You need to set the animation delegate to the view, controller, then have it implement the relevant callback.

Add these two lines:

basicAnimation.setValue("strokeEnd", forKey: "animationID")
basicAnimation.delegate = self

Then make sure you conform the view controller to CAAnimationDelegate protocol (by adding that after UIViewController in its declaration) and implement this delegate method:

override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
    if let animationID: Any = anim.valueForKey("animationID") {
        if animationID as String == "strokeEnd" {
            // Your code here
        }
    }
}

Credit to this answer

Chris
  • 4,009
  • 3
  • 21
  • 52