How can I correctly use a TabbedPage inside a NavigationPage

My app has one NavigationPage with a TabbedPage at its root. I want to hide the navigation bar based on the active tab. Unfortunately, Xamarin doesn't correctly resize my pages once the navigation bar moves in and out of view.

Here's the "bug" in a minimal reproduction:

image

Here's the reproduction's code:

public App()
{
    InitializeComponent();

    // Our tabs
    var bluePage = new ContentPage() { 
        Title = "Blue",
        BackgroundColor = Color.Blue 
    };
    var yellowPage = new ContentPage() { 
        Title = "Yellow",
        BackgroundColor = Color.Yellow 
    };
    var redPage = new ContentPage() { 
        Title = "Red",
        BackgroundColor = Color.Red 
    };


    // Tabbed page to hold tabs
    var tabbedPage = new TabbedPage()
    {
        Title = bluePage.Title,
        Children = {
            bluePage,
            yellowPage,
            redPage
        }
    };

    tabbedPage.CurrentPageChanged += (sender, e) =>
    {
        // Hide the app's navbar for the yellow page
        var shouldHaveNavigation = tabbedPage.CurrentPage != yellowPage;
        NavigationPage.SetHasNavigationBar(tabbedPage, shouldHaveNavigation);

        // Set page title to copy active tab
        tabbedPage.Title = tabbedPage.CurrentPage.Title;
    };


    var navPage = new NavigationPage(tabbedPage);

    MainPage = navPage;

}

I've tried to circumvent the issue by pushing three NavigationPages to the TabbedPage, but I understand this won't work on Android.

Is there a way to prevent the vertical layout glitch I'm currently seeing?

Best Answer

Answers

  • SimonJaspersSimonJaspers USMember ✭✭

    @AdrianKnight said:
    @SimonJaspers Pushing a tabbed page on to a navigation page is bad design. This is not recommended by Apple. In your case, you should only use a tabbed page as your main page (child tabs can be navigation pages). If you want to temporarily deviate from the tabbed page (say you have a login flow), then push pages modally onto the tabbed page. I believe modal pages can be navigation pages.

    Adrian, thank you for your reply. I've had a look at some of Apple's own iOS apps and confirmed that whenever a tab bar is used, the navigation stack seems to be inside (i.e. underneath) the tab control.

    However, I already briefly mentioned having tried NavigationPage instances as children of the TabbedPage and failing to get this to work in Android.

    Would the only solution then be to target Android/iOS specifically and build up the UI structure differently for each platform? And, as a follow up question: where would the single NavigationPage I'm allowed to have on Android be placed in my structure?

  • AdrianKnightAdrianKnight USMember ✭✭✭✭

    @SimonJaspers No. Two different structures sound like a nightmare. There should only be one. What kind of issue are you getting on Android? If you have a repro project, I can take a look. If you are trying to have one navigation page and multiple content pages, then it makes sense to house them all in a tabbed page. Android should work. Again, I'd like to hear about the issue you were having.

  • SimonJaspersSimonJaspers USMember ✭✭
    edited October 2016

    @AdrianKnight said:
    @SimonJaspers No. Two different structures sound like a nightmare. There should only be one. What kind of issue are you getting on Android? If you have a repro project, I can take a look. If you are trying to have one navigation page and multiple content pages, then it makes sense to house them all in a tabbed page. Android should work. Again, I'd like to hear about the issue you were having.

    I now have a test solution that works on both iOS and Android. Thanks for your help, Adrian! I'm not exactly sure what fixed the issue though... In my main project, I was getting this error:

    System.Exception: Android only allows one navigation page on screen at a time

    In my test solution, I'm now using this structure:

    TabbedPage
        NavigationPage
            ContentPage
        NavigationPage
            ContentPage
        NavigationPage
            ContentPage
    

    Within each of those ContentPage instances, I'm able to call Navigation.PushAsync and Navigation.PushModalAsync. When I push a modal page, I'm able to wrap in a new navigation page like so:

    await Navigation.PushModalAsync(new NavigationPage(new ContentPage()));
    

    I can now create nested page sequences in each of my tabs as well as in an overlay, which was my goal all along.

    I'm not sure why this is working now and wasn't before. It seems to me, that I'm still nesting NavigationPages. I also updated my Android emulator in the progress, so I guess I changed too many things at once...

    P.S.
    I also found some posts saying nested NavigationPages weren't an option in Android, so I kind of gave up on them (like this one & this one)

  • AdrianKnightAdrianKnight USMember ✭✭✭✭

    @SimonJaspers When you do NavigationPage / MasterDetailPage -> TabbedPage -> NavigationPage / MasterDetailPage (child), then you're indirectly nesting two navigations which is not allowed. :)

    TabbedPage
        NavigationPage
            ContentPage
        NavigationPage
            ContentPage
        NavigationPage
            ContentPage
    

    Looks good.

  • AndersMalmoAndersMalmo NOMember ✭✭
    edited June 2017

    @AdrianKnight said:
    @SimonJaspers When you do NavigationPage / MasterDetailPage -> TabbedPage -> NavigationPage / MasterDetailPage (child), then you're indirectly nesting two navigations which is not allowed. :)

    TabbedPage
        NavigationPage
            ContentPage
        NavigationPage
            ContentPage
        NavigationPage
            ContentPage
    

    Looks good.

    I've tried this, but both the tab icon & text is not visible on iOS...ideas?

  • Tim.3500Tim.3500 USMember ✭✭

    I have this same layout, adding Navigation Pages to the children of the Tabbed page. I want to switch tabs via button and I can't. I CAN if I simply add Content Pages to the children of the tabbed page...

    var parentPage = this.Parent as TabbedPage;
    parentPage.CurrentPage = parentPage.Children[0]; << works IF the tab was added as a ContentPage, like this:

    public MainTabbed()
    {
    mappage = new Map();
    mappage.Icon = "ic_map.png";
    mappage.Title = "Map";
    Children.Add(mappage);

            searchpage = new Search();
        searchpage.Icon = "ic_searche.png";
        searchpage.Title = "Search";
        Children.Add(searchpage);
    

    ......

    If I use:

    public MainTabbed()
    {
    mappage = new NavigationPage(new Map());
    mappage.Icon = "ic_map.png";
    mappage.Title = "Map";
    Children.Add(mappage);

            searchpage = new NavigationPage(new Search());
            searchpage.Icon = "ic_searche.png";
            searchpage.Title = "Search";
            Children.Add(searchpage);
    

    ......

    var parentPage = this.Parent as TabbedPage; << parentPage is null

    Any ideas?

  • Tim.3500Tim.3500 USMember ✭✭

    So if anyone else is duhhhh as me, it's: this.Parent.Parent

    var parentPage = this.Parent.Parent as TabbedPage;
    parentPage.CurrentPage = parentPage.Children[0];

  • connelblazeconnelblaze Member ✭✭

    hello, i have a little problem with this.
    i have a landing page, login, signup and dashboard.
    The dashboard is the tabbed page so already, it's in a navigation page because
    the rootpage is the mainpage(landing) where you have to choose login or signup

Sign In or Register to comment.