John Livermore
John Livermore

Reputation: 31333

Intercepting ios back button to send back to base view controller

We have a sequence of screens that navigate in order...

BaseViewController -> A -> B -> BaseViewController

Each screen uses NavigationController.PushViewController to go from...Base->A, A->B. So each subsequent screen is placed in the navigation stack.

So if you are on A and you click 'back', then it goes back one screen. This works well as it is controlled by the NavigationController.

enter image description here

However, when you are on screen B, 'back' should to back to the BaseViewController.

Instead it goes (as designed by Apple) back to A. Is there a way to intercept the 'back' button on B so we can instead use NavigationController.PopToViewController to send the user back to BaseViewController?

Upvotes: 0

Views: 1536

Answers (5)

John Livermore
John Livermore

Reputation: 31333

Thanks for all the answers. @Cole Xia put me on the right path for our scenario. His technique works, and the following works as well.

Here is the Xamarin code. The technique is to replace the current list of ViewControllers with a new one. Then when 'back' is hit on B, it goes right back to BaseViewController.

var viewControllers = new UIViewController[] { NavigationController.ViewControllers[0], new B() };
NavigationController.SetViewControllers(viewControllers, false);

Upvotes: 0

Au Ris
Au Ris

Reputation: 4669

If I understand correctly you want to pop to root view controller from a certain top view controller. One way to do it would be to create a subclass of UINavigationController and override popViewController method where you would check what you have on top at the moment and decide to pop to root or not. Here's an example:

open class CustomNavigationController: UINavigationController {
    override open func popViewController(animated: Bool) -> UIViewController? {
        if topViewController is BViewController {
            return popToRootViewController(animated: animated)?.last
        } else {
            return super.popViewController(animated: animated)
        }
    }
}

Upvotes: 1

ColeX
ColeX

Reputation: 14463

  1. As @the4kman mentioned , we can create a custom button to replace the LeftBarButtonItem ,and handle the back event .

ViewDidLoad in B

this.NavigationItem.LeftBarButtonItem = 
    new UIBarButtonItem("back", UIBarButtonItemStyle.Plain, (sender,e) => {
        UIViewController baseVC = NavigationController.ViewControllers[NavigationController.ViewControllers.Length - 3];
        NavigationController.PopToViewController(baseVC, true);
});
  1. As @J.C. Chaparro mentioned , remove A from stack .

ViewDidLoad in B

List<UIViewController> list = NavigationController.ViewControllers.ToList<UIViewController>();
list.RemoveAt(list.Count-2);
NavigationController.ViewControllers = list.ToArray();

Upvotes: 1

J.C. Chaparro
J.C. Chaparro

Reputation: 1079

You can do something like this in B's viewDidAppear function:

guard let navigationController = self.navigationController else {
    return
}
navigationController.viewControllers.remove(at: navigationController.viewControllers.count - 2)

This will remove A from the stack, and allow you to go back to BaseViewController from B.

Upvotes: 1

user1046037
user1046037

Reputation: 17725

Approach:

  • Use child view controllers

Steps:

  1. Create a view controller C which is a subclass of Base
  2. Add A as a child view controller to C
  3. Create a view controller D which is a subclass of Base
  4. Add B as a child view controller to D
  5. Push C to D

Upvotes: 0

Related Questions