Chris
Chris

Reputation: 1642

Prevent closing by hardware back button in xamarin forms on android

I want to prevent closing the app by pressing the hardware back button in xamarin forms on android.

I want, that you can navigate with the hardware back button in the app (what is working), but do not want to exit, when the first page in navigation stack is reached.

I tried to use the OnSleep event in xamarin forms, but here I can not cancel the exit.

I also tried catching the back button in android:

    public override void OnBackPressed()
    {
        //base.OnBackPressed();
    }

But when using xamarin forms, I do not know which page is currently showing. So I do not know if the navigation back is allowed or not

Upvotes: 21

Views: 25646

Answers (7)

Morse
Morse

Reputation: 9144

Expanding Chris's answer as there is no App.Instance now and one cannot access App in a static manner within platform code.

1. App.xaml.cs in the Shared project

public bool DoBack 
{
    get 
    {
        return MainPage.Navigation.NavigationStack.Count > 1;
    }
}

2.MainActivity.cs in the Android project

  • Declare a variable in the class:
App app;
  • In OnCreate(Bundle bundle) change LoadApplication(new App()); to:
app = new App();
LoadApplication(app);
  • Override the OnBackPressed() method:
public override void OnBackPressed()
{
    if (app.DoBack)
    {
        base.OnBackPressed();
    }
}

Upvotes: 4

Noe Miranda Franco
Noe Miranda Franco

Reputation: 83

You can use this nuget chd.hwBackButtonManager nuget

github project

Upvotes: 0

Francesco
Francesco

Reputation: 5183

The solution proposed can work nicely, but I don't like "static property exposure" to solve problems. More over, I don't like the usage of "properties as methods" solutions, especially when a lot of logic is involved.

The main problem here how we can handle the OnBackButton() method from our Xamarin.Forms.Application class.

What about doing the same thing in a more elegant way?

First you need to extend the Xamarin.Forms.Application class like this:

namespace YourNameSpace
{
    public class Application : Xamarin.Forms.Application
    {
        #region Public Methods

        public bool HandleBackButton()
        {
            return OnBackPressed();
        }

        #endregion

        #region Application Methods

        protected virtual bool OnBackPressed()
        {
            return false;
        }

        #endregion
    }
}

Your App implementation now will use this class as base class. Remember to modify your xaml and your xaml.cs accordingly:

<common:Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:common="clr-namespace:YourNameSpace"
             x:Class="YourNameSpace.App">
</common:Application>

In your App.cs implementation you can now override the OnBackButton() method.

public partial class App : YourNameSpace.Application
{
    #region Constructors

    public App()
    {
        InitializeComponent();
    }

    #endregion

    #region App Methods

    protected override bool OnBackPressed()
    {
        // Handle when the back button is pressed
        return false;
    }

    #endregion
}

Then you need to change a little your Activity class implementation.

public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
    #region Constants and Fields

    private App _app;

    #endregion

    #region Activity Methods

    protected override void OnCreate(Bundle bundle)
    {
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;

        base.OnCreate(bundle);

        global::Xamarin.Forms.Forms.Init(this, bundle);

        _app = new App();
        LoadApplication(_app);
    }

    public override void OnBackPressed()
    {
        if(!_app.HandleBackButton())
            base.OnBackPressed();
    }

    #endregion
}

Upvotes: 0

Senthamizh
Senthamizh

Reputation: 381

Just give a blank call in the page where do you wanna prevent, like

protected override bool OnBackButtonPressed()
{
return true;
}

This will prevent the back button in XF-Droid.

Upvotes: 10

Chris
Chris

Reputation: 1642

It works with evaluating the NavigationStack (when you use NavigationPage).

In my Activity, I override the OnBackPressed

public override void OnBackPressed()
{
    if(App.Instance.DoBack)
    {
        base.OnBackPressed();
    }
}

In my xamarin forms app (App.Instance (it is a singleton)), I will evaluate the NavigationStack of the current Page like this.

public bool DoBack
{
    get
    {
        NavigationPage mainPage = MainPage as NavigationPage;
        if (mainPage != null)
        {
            return mainPage.Navigation.NavigationStack.Count > 1;
        }
        return true;                
    }
}

When there is only one page left in the NavigationStack I will not call base.OnBackPressed, so that I will not close the App.

![test]

Upvotes: 20

Iain STIRZAKER
Iain STIRZAKER

Reputation: 331

And here's what the code could look like for a Xamarin Forms MasterDetail page scenario...

    public bool DoBack
    {
        get
        {
            MasterDetailPage mainPage = App.Current.MainPage as MasterDetailPage;

            if (mainPage != null)
            {    
                bool canDoBack = mainPage.Detail.Navigation.NavigationStack.Count > 1 || mainPage.IsPresented;

                // we are on a top level page and the Master menu is NOT showing
                if (!canDoBack)
                {
                    // don't exit the app just show the Master menu page
                    mainPage.IsPresented = true;
                    return false; 
                }
                else
                {
                    return true;
                }                    
            }
            return true;
        }
    }

Upvotes: 12

Alex.F
Alex.F

Reputation: 6201

Here is a solution that works on Android.
Introduce a counter in the application class and increment it with each OnStart and decrement it with each OnStop this way when the counter is 1 you'll know you are at your last activity.

Needless to say, use a base activity implementation so that you don't have to copy-past boiler plate code.

Upvotes: 0

Related Questions