0

I am using a UINavigationController with a different Controller. I have overridden the BackButton from the Navigation. In some cases I want to jump to RootController if BackButton is tapped.

But in this case the user jumps Back, but the whole View is empty. The behaviour is strange and I don’t know why. Can someone help me please.

To go to RootController I do the following.

if([self.tempnavigationInfo.refkey isEqual:@"main"]){
    [self.navigationController popToRootViewControllerAnimated:NO];
}

For the BackButton I have implemented this handler:

@implementation UINavigationController (ShouldPopOnBackButton)

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {

    if([self.viewControllers count] < [navigationBar.items count]) {
        return YES;
    }

    BOOL shouldPop = YES;
    UIViewController* vc = [self topViewController];
    if([vc respondsToSelector:@selector(navigationShouldPopOnBackButton)]) {
        shouldPop = [vc navigationShouldPopOnBackButton];
    }

    if(shouldPop) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self popViewControllerAnimated:YES];
        });
    } else {
        // Workaround for iOS7.1
        for(UIView *subview in [navigationBar subviews]) {
            if(subview.alpha < 1.) {
                [UIView animateWithDuration:.25 animations:^{
                    subview.alpha = 1.;
                }];
            }
        }
    }

    return NO;
}

In the ViewController I handle it this way:

-(BOOL) navigationShouldPopOnBackButton {
 if (self.backConfirmation != nil
              && self.backConfirmation.navigation != nil
              && self.backConfirmation.confirmation == nil){
        [[NSNotificationCenter defaultCenter] postNotificationName:@"gotoWithoutConfirmation" object:self.backConfirmation.navigation];
        return NO;
    }
    return YES;
}

In my MainController I catch the notification and call the method with "popToRoot" logic above:

-(void) handleNotificationFromFormView:(NSNotification*) notification
{
    if([notification.name isEqualToString:@"gotoWithoutConfirmation"]){
        self.tempnavigationInfo = (NavigationInfo*)notification.object;
        [self goBackTo];
}
BHuelse
  • 2,889
  • 3
  • 30
  • 41

1 Answers1

0

in case anyone else ends up here - I had a similar issue that confused me for a while - it turned out to be because I was using a custom transition that moved the content of the root vc off screen. Popping to root without specifying a transition to reverse the translation means the root comes back with with its content off screen - it doesn't get reset to its default state automatically.

For example - if you set a custom transition using a UINavigationControllerDelegate like this:

class NavigationControllerDelegate: NSObject, UINavigationControllerDelegate {

 func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {

    if let _ = fromVC as? FirstVC, let _ = toVC as? SecondVC {
      return SlideTransitionAnimator(direction: .left)
    } 
}

and your transition class does some transformation to the rootViewController - eg, as in my case, moving it off screen:

class SlideTransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning {
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {

    guard let fromView = transitionContext.view(forKey: .from),
      let toView =  transitionContext.view(forKey: .to) else {return }

    let containerView = transitionContext.containerView
    containerView.addSubview(toView)
    switch direction  {
      case .left:
        toView.frame.origin.x = toView.frame.size.width
      default:
        toView.frame.origin.x = -toView.frame.size.width
    }

    UIView.animate(withDuration: 1,delay: 0, options: .curveEaseInOut,
                   animations: {
                     fromView.alpha = 0
                     switch self.direction  {
                       case .left:
                         fromView.frame.origin.x -= fromView.frame.size.width
                       default:
                         fromView.frame.origin.x += fromView.frame.size.width
                     }
                     toView.alpha = 1.0
                     toView.frame.origin.x = 0
    },
                   completion: { _ in
                     transitionContext.completeTransition(true)
    })

  }
}

if you don't reverse this animation or reset it when calling popToRootViewController you can end up with a seemingly empty root view controller.

RadioLog
  • 582
  • 1
  • 4
  • 20
Sam Woolf
  • 81
  • 7