1

I have the following small function wich contains two primary actions which I would like to occur. A three second animation, and then upon completion of that animation, another function call. What is happening, however, is that the line of code that calls another function is being executed before the UIView animation has completed.

func switchToNormalState() {

    print("Switching to Normal State")
    currentState = "normal"
    intervalCounter = intervalCounter + 1

    setVisualsForState()

    UIView.animateWithDuration(Double(normalDuration), animations: { () -> Void in
        self.ProgressBar.setProgress(1.0, animated: true)
        }, completion: { _ in
            self.switchToFastState()
    })

}

I have studied other similar posts looking for the solution but none of the solutions have solved my puzzle. What am I doing wrong in the completion block in order to make these actions a sequence and not simultaneous?

zeeple
  • 5,509
  • 12
  • 43
  • 71
  • I think that this happens because progressBar also have animation so I think that completion block execute as soon as animation block run. But funtion run fast because progress bar is in animation process. – Mudith Chathuranga Silva May 19 '16 at 03:46
  • What @ChathurangaSilva says is correct. Why are you using a UIView animation block for this anyway? The progress bar has its own animations. – Daniel van der Merwe May 19 '16 at 03:47

2 Answers2

3

Assuming that ProgressBar is a UIProgressView, the setProgress method animates itself and doesn't need to be contained in a UIView.animateWithDuration call.

This means the setProgress animation is probably longer than the duration you're putting in the UIView.animateWithDuration call, so self.switchToFastState() is being called when the UIView animation ends- before the setProgress animation completes.

Solutions

  1. Change the duration. You can hack around this by finding/guessing the duration of the setProgress animation and using that as your UIView animation duration. This should mimic the behavior you are going for.

  2. Change the duration but use GCD. This is the same idea as above, but doesn't use the UIView animation method. You can see this question for how to use GCD.

  3. NSTimer or Subclassing. There are solutions here that use NSTimer or subclass UIProgressView.

Community
  • 1
  • 1
Carter
  • 3,053
  • 1
  • 17
  • 22
  • That's what I'm talking about ! clearly explained the situation. – Mudith Chathuranga Silva May 19 '16 at 03:52
  • Great answer, but I think solution #1 is super hacky and should be removed. Just used GCD or NSTimer for this! – Daniel van der Merwe May 19 '16 at 03:57
  • Thank you very much for the attempt to answer my question. The reason I do not want to use NSTimer in conjunction with the progress view is because it results in a very jerky experience as the progress lurches from left to right. – zeeple May 19 '16 at 05:01
  • @zeeple No problem. you can just use Solution #1 or #2 then, they both use the native `setProgress` animation that is what you are looking for. – Carter May 19 '16 at 05:05
  • @DanielvanderMerwe Thanks, I agree that #1 is hacky- I'm keeping it in case people are animating other UI elements at the same time. – Carter May 19 '16 at 05:08
2

I am not sure if this is the best solution, but this is what I ended up going with:

        ProgressBar.progress = 1.0
        UIView.animateWithDuration(Double(normalDuration), animations: { () -> Void in
            self.ProgressBar.layoutIfNeeded()
            }, completion: { (_) -> Void in
                self.switchToFastState()
        })

This solution removes the setProgress (which may be animated) from the animation block and this allows the UIView animation to execute without interuption.

zeeple
  • 5,509
  • 12
  • 43
  • 71