Reputation: 1642
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
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
App app;
OnCreate(Bundle bundle)
change LoadApplication(new App());
to:app = new App();
LoadApplication(app);
OnBackPressed()
method:public override void OnBackPressed()
{
if (app.DoBack)
{
base.OnBackPressed();
}
}
Upvotes: 4
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
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
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
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
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