Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect when UINavigationController animation has finished?

I hope this is a simple question. If I have a UINavigationController and I push a new view controller onto the stack with an animated transition, how can I detect when the animation has finished and the new view controller is on screen?

I have a few scenarios where I need to push a new controller that then has to do a long-running operation. I'd like to push the new view first so there's something on screen before I start blocking the main thread for a long time. If I do the push immediately followed by my long-running task the view won't show up until after both are done of course and the main thread is able to process events again.

So, what I'd like to do be able to detect in the new controller once the animation is done and the view is on screen, and then start the task.

like image 825
eodabash Avatar asked Apr 14 '12 01:04

eodabash


People also ask

How to check if the animation is complete?

You can check if the animation is complete by looking at the normalizedTime property of the Animator's AnimatorStateInfo: if (pc_anim.GetCurrentAnimatorStateInfo (0).IsName ("attack") && pc_anim.GetCurrentAnimatorStateInfo (0).normalizedTime >= 1.0f) { pc_atttacking = false; pc_anim.SetBool ("attack", false); }

Is there a way to check if animator is in state end?

There is no "StateEnded" or "TransitionEnded" event for now on the mecanim system... So the only way to do that is to pull the "CurrentAnimatorStateInfo" and check if you enter the state/leave it. if(this.animator.GetCurrentAnimatorStateInfo(0).IsName("YourAnimationName")) { // Avoid any reload.

Is it possible to have events in animator States?

I believe you can edit your animator states or transitions (I forget which; possibly both) to have events, causing them to call specific functions in your code when they reach a particular point. Chocolade likes this.

What is the difference between a transition and an animation?

The above solution can be slightly tweaked to account for animations done with keyframes. Like transitions have the transitionend event, animations have the animationend event. We’ll take the whichtransitionEvent function and swap out instances of transition for animation (case sensitive).


Video Answer


2 Answers

+1 to @DHamrick's recommendation for not blocking the main thread at all.

To answer the original question, you can detect viewController changes in two places:

  1. The viewController you just pushed will receive viewWillAppear: and viewDidAppear: messages. If you want to know when a specific viewController appears, implement these methods.

  2. The navigationController:didShowViewController:animated: method mentioned by @Mike Z is sent to the navigationController's delegate. You will need to assign an object to be that delegate in order to receive this message. You will then know every time a viewController appears.

like image 113
Cowirrie Avatar answered Sep 19 '22 17:09

Cowirrie


Instead of blocking the main thread, you should look in to doing your long running operation inside of another thread or even better, using a GCD queue.

dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, NULL);
dispatch_async(backgroundQueue, ^{
    // Do your long running code
    dispatch_async(dispatch_get_main_queue(), ^{
        //Update your UI
    });
});

You can put this code in your viewDidLoad: so that you know your UI has already loaded. This also means you don't have to rely on the timing of the animation.

like image 31
DHamrick Avatar answered Sep 20 '22 17:09

DHamrick