13

I want to mark that my UINavigationController is animating (push/pop) or not.

I have a BOOL variable (_isAnimating), and the the code below seem work:

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    _isAnimating = YES;
}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    _isAnimating = NO;
}

But it work incorrectly in iOS7 with swipe gesture. Assume my navigation is: root-> view A -> view B . I'm currently on B.

  • In begin of swipe (go back from B to A), the funcion "navigationController:willShowViewController:animated:(BOOL)animated" is called, then _isAnimating = YES.

  • The normal case is the swipe is finished (go back to A), the function "navigationController:didShowViewController:animated:(BOOL)animated" is called, then _isAnimating = NO. This case is OK, but:

  • If the user may just swipe a half (half transition to A), then don't want to swipe to the previous view (view A), he go to the current view again (stay B again). Then the function "navigationController:didShowViewController:animated:(BOOL)animated" is not called, my variable has incorrect value (_isAnimating=YES).

I have no chance to update my variable in this abnormal case. Is there any way to update the state of navigation? Thank you!

DipakSonara
  • 2,598
  • 3
  • 29
  • 34
vietstone
  • 8,784
  • 16
  • 52
  • 79
  • Have you tried using the isBeingPresented property of UIViewController? – henryeverett May 20 '14 at 08:24
  • Chào! Did you try `viewWillAppear:`? – Thanh-Nhon Nguyen May 20 '14 at 08:28
  • @henryeverett and Thanh-NhonNGUYEN isBeingPresented and viewWillAppear: is inside A or B. My code is not A or B, it's another class (it's delegate of UINavigationController, it's role is navigation manager). Beside, my code may have many view, there're A, B, C, D, ..... not only A and B – vietstone May 20 '14 at 08:39
  • Why don't you just keep track of the variable in the viewWillAppear:(BOOL)animated and viewWillDisappear:(BOOL)animated methods of respective VCs? Add a delegate protocol and make the VCs conform to it. That should make your manager capable of receiving callbacks from the VCs if that's what you want. – Widerberg May 20 '14 at 08:59
  • @camdaochemgio you got any solution. I'm running into the same issue – Tariq Aug 20 '14 at 06:32
  • @Tariq Have you resolved it? I had a solution for this. If you still stuck, we can talk – vietstone Sep 04 '14 at 07:38
  • @camdaochemgio Could you add that solution as an answer? If you do it within 3 days, you will get the bounty of 50 rep. – vrwim Dec 20 '15 at 15:03

1 Answers1

4

The clue to solve you problem can be found in the interactivePopGestureRecognizer property of UINavigationController. This is the recognizer which responds for popping controllers with a swipe gesture. You can notice that the state of the recognizer is changed to UIGestureRecognizerStateEnded when the user rises finger up. So, additionally to Navigation Controller delegate you should add target to the Pop Recognizer:

UIGestureRecognizer *popRecognizer = self.navigationController.interactivePopGestureRecognizer;
[popRecognizer addTarget:self                       
                  action:@selector(navigationControllerPopGestureRecognizerAction:)];

This action will be called each time the Pop Recognizer changed, including the end of a gesture.

- (void)navigationControllerPopGestureRecognizerAction:(UIGestureRecognizer *)sender
{
    switch (sender.state)
    {
        case UIGestureRecognizerStateEnded:

        // Next cases are added for relaibility
        case UIGestureRecognizerStateCancelled:
        case UIGestureRecognizerStateFailed:

            _isAnimating = NO;
            break;

        default:
            break;
    }
}

P.S. Do not forget that the interactivePopGestureRecognizer property is available since iOS 7!

kelin
  • 11,323
  • 6
  • 67
  • 104
  • I'm not very good with `UINavigationController`s, how can I detect whether the first or the second view controller will be shown after the animation ended? I have tried using the `navigationController` property, but it is null inside the method. Also the state is not useful, it is always ended in my tests. Any idea how I can detect this? – vrwim Dec 22 '15 at 21:31
  • What do you mean by "the first" and "the second' controllers? If you need to understand, whether the user has finished the gesture, or not, you can add a flag `_swipeCompleted` and set it to `YES` inside the `didShowViewController` method. You also may look at `viewControllers` property of the Navigation Controller, it always contain all controllers in the stack. And if you need to know which controller will be shown *before* the animation ends, use variable `viewController` which is passed to `willShowViewController`. – kelin Dec 23 '15 at 12:25