Change Back Button Assignment

How can I change the view controller to which the default navigation back button takes me? The back button usually returns you to the previous controller. But what if I want him to return with two controllers? I mean, I want to change the view controller to which the back button returns me. I do not prefer to create a custom return button. So is there another way? Probably unleash the segment associated with the back button or something else?

+6
source share
4 answers

Probably the easiest way to achieve the desired behavior is to use navigationController.setViewControllers(controllers, animated: true) .

If you want to return 2 controllers from controller A instead of one, use this user segment when presenting A:

 class ReplaceControllerSegue: UIStoryboardSegue { override func perform() { if let navigationController = sourceViewController.navigationController as UINavigationController? { var controllers = navigationController.viewControllers controllers.removeLast() controllers.append(destinationViewController) navigationController.setViewControllers(controllers, animated: true) } } } 

Here is a good tutorial on how to set a custom class for your segue in Interface Builder: http://blog.jimjh.com/a-short-tutorial-on-custom-storyboard-segues.html

If you represent the controller by code, use this category:

 extension UINavigationController { func replaceCurrentViewControllerWith(viewController: UIViewController, animated: Bool) { var controllers = viewControllers controllers.removeLast() controllers.append(viewController) setViewControllers(controllers, animated: animated) } } 

Then just use self.navigationController!.replaceCurrentViewControllerWith(newController, animated: true) instead of self.navigationControllerPushViewController(newController, animated: true) .

It's easy to tweak this code to remove as many controllers as you need.

+6
source

You can override willMoveToParentViewController . This method is called before your view controller has been added or removed from the container view controller (for example, UINavigationController ). When it is added, the parent parameter contains the container view controller; when it is deleted, the parent parameter is zero.

At this point, you can remove (without animation) the second controller of the last view in the navigation stack as follows:

Objective-c

 - (void)willMoveToParentViewController:(UIViewController *)parent { [super willMoveToParentViewController:parent]; if (parent == nil) { NSArray *viewControllers = self.navigationController.viewControllers; NSUInteger viewControllersCount = viewControllers.count; if (viewControllersCount > 2) { NSMutableArray *mutableViewControllers = [NSMutableArray arrayWithArray:viewControllers]; [mutableViewControllers removeObjectAtIndex:(viewControllersCount - 2)]; [self.navigationController setViewControllers:[NSArray arrayWithArray:mutableViewControllers] animated:NO]; } } } 

Swift

 override func willMoveToParentViewController(parent:UIViewController?) { super.willMoveToParentViewController(parent) if (parent == nil) { if let navigationController = self.navigationController { var viewControllers = navigationController.viewControllers var viewControllersCount = viewControllers.count if (viewControllersCount > 2) { viewControllers.removeAtIndex(viewControllersCount - 2) navigationController.setViewControllers(viewControllers, animated:false) } } } } 

You can also delete several or add new ones. Just make sure that when you are finished, your array contains at least 2 view controllers with the last invariable (the last one is deleted, and after this method is automatically called, it is automatically deleted from the array).

Also note that this method can be called more than once with the nil parameter. For example, if you try to display the view controller by dragging the edge, but interrupt it in the middle, the method will be called every time you try. Be sure to add additional checks to make sure that you do not remove more view controllers than you want.

+6
source

You can do this by adding a custom back button like this one. Add your custom handler by clicking on the back button in the navigation bar.

 + (void)addCustomBackButtonForController:(id <MyCustomBackButtonDelegate>)iViewController withNavBar:(UINavigationController *)iNavController andNavItem:(UINavigationItem *)iNavItem { if ([self isIOS7orAbove]) { UIImage *backArrow = [UIImage imageNamed:kMyIOS7BackButtonImage]; UIButton *aBackButton = [UIButton buttonWithType:UIButtonTypeSystem]; CGSize aBackButtonTextSize = [MyLocalizedBackButton sizeWithFont:[UIFont systemFontOfSize:17.0]]; aBackButton.frame = CGRectMake(0.0, 0.0, aBackButtonTextSize.width + backArrow.size.width, iNavController.navigationBar.frame.size.height); aBackButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; SEL backSelector = NSSelectorFromString(@"backAction"); [aBackButton addTarget:iViewController action:backSelector forControlEvents:UIControlEventTouchUpInside]; [aBackButton setTitle:MyLocalizedBackButton forState:UIControlStateNormal]; [aBackButton setImage:backArrow forState:UIControlStateNormal]; [aBackButton setExclusiveTouch:YES]; if ([self isIOS7orAbove]) { aBackButton.titleLabel.font = [UIFont systemFontOfSize:17.0]; } else { aBackButton.titleLabel.font = [UIFont boldSystemFontOfSize:12.0]; } UIBarButtonItem *aLeftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:aBackButton]; UIBarButtonItem *aNegativeSpacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; aNegativeSpacer.width = kMyIOS7BarButtonNegativeSpacerWidth; iNavItem.leftBarButtonItems = @[aNegativeSpacer, aLeftBarButtonItem]; } else { UIButton *aCustomBackButton = [UIButton buttonWithType:101]; SEL backSelector = NSSelectorFromString(@"backAction"); [aCustomBackButton addTarget:iViewController action:backSelector forControlEvents:UIControlEventTouchUpInside]; [aCustomBackButton setTitle:MyLocalizedBackButton forState:UIControlStateNormal]; [aCustomBackButton setExclusiveTouch:YES]; if ([self isIOS7orAbove]) { aCustomBackButton.titleLabel.font = [UIFont systemFontOfSize:kFontSize17]; } else { aCustomBackButton.titleLabel.font = [UIFont boldSystemFontOfSize:kFontSize12]; } UIBarButtonItem *aLeftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:aCustomBackButton]; iNavItem.leftBarButtonItem = aLeftBarButtonItem; } } 
0
source

This may just repeat the above, but I solved it by changing the viewDidLoad in the latest VewController. "Controllers" is an array of type UIViewController. In my case, I just wanted to go back to the root view controller, so the array just contains the root view manager (first) and the current view manager (last). Then "setViewControllers" replaces the current stack with the one I created.

 override func viewDidLoad() { super.viewDidLoad() var theControllers = [UIViewController]() theControllers.append(self.navigationController!.viewControllers.first!) theControllers.append(self.navigationController!.viewControllers.last!) self.navigationController?.setViewControllers(theControllers, animated: false) } 
0
source

All Articles