NavigationPage - Remove a page from the "back stack"

rmevans9rmevans9 USMember

Hello everyone!

First of all i would like to say I am loving the new updates!

Ok, so I am working on an application that I do some processing during load of the application so I start on a Splash Screen. Once the processing is complete I take the user to one of two other Pages depending on the results of my processing. This works wonderfully.... except that I push the Splash Screen onto a NavigationPage in my GetMainPage function call as I want to use the Navigation page for the rest of the application. What this allows the user to do is hit their back button from the page I push them on to and it takes them back to the Splash Screen! I am in search of a way to make the navigation page essentially ignore the Splash Screen page. I thought of two ways this is possible but am not sure if either are possible...

  1. Don't use the NavigationPage in the GetMainPage call. Use some other Page type to display the Splash Screen. Once I am ready to move on switch to a NavigationPage then. I think this would be awesome except that I don't know if I can do it... is it possible to change to a NavigationPage after handing a different type on the GetMainPage function call?
  2. Have a function call to either erase the Navigation History or purge a specific page from the history. I did not see any way to do this unless I missed something...

Any help on keeping a page out of the navigation history would be greatly appreciated!

Posts

  • hatchhatch USMember ✭✭

    Any luck with this? I'm running into the exact same issue trying to get a user authentication system working.

  • rmevans9rmevans9 USMember

    I actually took another approach. I am starting the view off with what my splash screen would look like then binding a few visible properties to the view model I am using (using a MVVM setup from the TodoMVVM example floating around) so once the ViewModel is done processing it either flips to show the controls or pushes the next screen. For my use case this works.

  • rene_ruppertrene_ruppert DEXamarin Team, University, XamUProfessors Xamurai

    Instead of making the splash your main screen, make the 2nd one the main screen, then show the splash screen modally and don't push it. When your 2nd screen re-appears, update it.

  • FabianoFranaFabianoFrana BRMember

    My main screen is a ContentPage. I open a login page (Another ContentPage) using the Navigation.PushModalAsync method. The device's back button keeps coming back to the main screen. How do I block this behavior?

  • hatchhatch USMember ✭✭

    This is exactly what I'm doing and have the same problem.

    On Android you want the user to be able to press the (physical) back button from the "top" screen to exit the application. If you place the sign on screen first and the user hits the back button after signing in they are returned to the sign on page (a regular Android activity allows you to exclude an activity from the history stack, but I haven't figured out how to do this using XF). If you put the home screen first and pop up the sign on page you've got the opposite problem. You really want the program to close in this case if they haven't signed in, but instead you end up back on the home page (not signed on).

  • JamesMontemagnoJamesMontemagno USForum Administrator, Xamarin Team, Developer Group Leader Xamurai
    edited June 2014

    There is a few ways of doing this.

    1.) You could do a custom page renderer and mark it as NoHistory and disable the arrows and such correctly. You would want to mark the Activity flags correctly. That is a bit tricky.

    2.) You could go the route of having a native login screen and then navigating to the main page. Then if you need to to go back to the login screen you could go ahead and navigate back to the login screen via an intent and pop of the top via android directly: Check out the Intent flags: https://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_CLEAR_TASK I would say in general this is the best way to do a splash screen too.

    using System;
    
    using Android.App;
    using Android.Content;
    using Android.Runtime;
    using Android.Views;
    using Android.Widget;
    using Android.OS;
    
    using Xamarin.Forms.Platform.Android;
    
    
    namespace AndroidLogin.Droid
    {
    
        [Activity (Label = "LoginPage", NoHistory =true, MainLauncher = true)]
        public class LoginActivity : Activity
        {
            protected override void OnCreate (Bundle bundle)
            {
                base.OnCreate (bundle);
                SetContentView (Resource.Layout.Main);
                var button = FindViewById<Button> (Resource.Id.myButton);
    
                button.Click += (sender, e) => 
                {
                    var intent = new Intent(this, typeof(MainActivity));
                    StartActivity(intent);
                };
            }
        }
    
        [Activity (Label = "AndroidLogin.Android.Android")]
        public class MainActivity : AndroidActivity
        {
            protected override void OnCreate (Bundle bundle)
            {
                base.OnCreate (bundle);
    
                Xamarin.Forms.Forms.Init (this, bundle);
    
                SetPage (App.GetMainPage ());
            }
        }
    }
    
  • Shameel.ktShameel.kt INMember

    Hi Fabiano França,

    I have the same problem. Is there any solution you got for iOS?

    Please update with me.

  • @ ThomasHuijzer, your solution do the job. Thanks a lot ;).

  • Sreeraj.0276Sreeraj.0276 USMember ✭✭

    Application.Current.MainPage=new LoginPage();

    If we are navigating like this to the Login Page, LoginPage will be set as the mainpage and there won't be an available backward navigation. On pressing the back button app will exit. But for setting splashscreen in android the right method is as explained by @JamesMontemagno . To set SplashActivity as MainLauncher decorate it with NoHIstory=true. And for iOS you can set a Storyboard as Splash screen

  • JamesParker.3081JamesParker.3081 USMember

    Really, there is no way to remove a page from the stack easily? This is very inconvenient.

  • praveenaHMpraveenaHM USMember ✭✭

    Hi Sreeraj,

    Your solution worked for me, Thanks a lot.

  • rudyrykrudyryk RUMember ✭✭✭
    edited October 2016

    I faced the same problem, but without NavigationPage.

    My pages structure is like that:

    RootPage > LoginPage (presented modally)

    after user login I just dismiss login page and push a new main page modal:

    RootPage > MainPage (presented modally)

    It works nice both on iOS and Android, all transitions are animated, RootPage has a nice background - everything's great!

    But on pressing "hardware" back button on Android, the main page just gets popped!

  • rudyrykrudyryk RUMember ✭✭✭
    edited October 2016

    I probably know how to handle the issue.

    As I can see there's no way to call default Activity.OnBackPressed() manually from the main activity FormsApplicationActivity class.

    The related source code:
    Xamarin.Forms.Platform.Android/FormsApplicationActivity.cs#L60

    public override void OnBackPressed()
    {
        if (BackPressed != null && BackPressed(this, EventArgs.Empty))
            return;
        base.OnBackPressed();
    }
    

    BackPressed is delegated to page's OnBackButtonPressed() which can be overridden - but we must know exactly which page class to override. I added OnBackButtonPressed() to all pages subclasses that are displayed and watched which is called :)

    But here's a pitfall! We can't override OnBackButtonPressed() for a content page subclass to just return false because in that case it will fallback to NavigationPage.OnBackButtonPressed():

    protected override bool OnBackButtonPressed()
    {
        if (CurrentPage.SendBackButtonPressed())
            return true;
    
        if (((INavigationPageController)this).StackDepth > 1)
        {
            SafePop();
            return true;
        }
    
        return base.OnBackButtonPressed();
    }
    

    So we need override NavigationPage.OnBackButtonPressed() and check manually its navigation stack size.

  • Sumit.SharmaSumit.Sharma INMember ✭✭

    I don't want to use navigation page in my application
    @ThomasHuijzer after using your method i am getting this exception

    System.InvalidOperationException: InsertPageBefore is not supported globally on Android, please use a NavigationPage.

    what to do?

  • MichaelPortMichaelPort USMember

    I used this.Finish() to close the activity I don't want in the stack as I'm loading the next view. I also overrode OnBackPressed) to load the correct page as needed.

  • HarshithaLSHarshithaLS USMember ✭✭
                for ( int PageIndex = Navigation.NavigationStack.Count; PageIndex >= 1; PageIndex--)
                {
                        Navigation.RemovePage(Navigation.NavigationStack[PageIndex]);
                }
    

    Removes all the page in navigation stack excluding main page or page at top of stack

Sign In or Register to comment.