Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle/cancel back navigation in Xamarin Forms

Tags:

I tried to use the back navigation by overriding OnBackButtonPressed, but somehow it wasn't get called at all. I am using the ContentPage and the latest 1.4.2 release.

like image 613
imgen Avatar asked Jun 05 '15 02:06

imgen


People also ask

How do I go back in xamarin form?

With the launch of Xamarin. Forms 4.6 came a brand new way to navigate backwards and can be combined with query properties. To navigate backwards you can use the same navigation patterns you are used to in terminal or the command line with `..`. That is right, just use `..` and a page will be popped from the stack.

What is Shell in xamarin forms?

Xamarin. Forms Shell reduces the complexity of mobile application development by providing the fundamental features that most mobile applications require, including: A single place to describe the visual hierarchy of an application. A common navigation user experience.


1 Answers

Alright, after many hours I figured this one out. There are three parts to it.

#1 Handling the hardware back button on android. This one is easy, override OnBackButtonPressed. Remember, this is for a hardware back button and android only. It will not handle the navigation bar back button. As you can see, I was trying to back through a browser before backing out of the page, but you can put whatever logic you need in.

  protected override bool OnBackButtonPressed()     {         if (_browser.CanGoBack)         {             _browser.GoBack();             return true;         }         else         {             //await Navigation.PopAsync(true);             base.OnBackButtonPressed();             return true;         }     } 

#2 iOS navigation back button. This one was really tricky, if you look around the web you'll find a couple examples of replacing the back button with a new custom button, but it's almost impossible to get it to look like your other pages. In this case I made a transparent button that sits on top of the normal button.

[assembly: ExportRenderer(typeof(MyAdvantagePage), typeof  (MyAdvantagePageRenderer))] namespace Advantage.MyAdvantage.MobileApp.iOS.Renderers {     public class MyAdvantagePageRenderer : Xamarin.Forms.Platform.iOS.PageRenderer     {         public override void ViewWillAppear(bool animated)         {             base.ViewWillAppear(animated);              if (((MyAdvantagePage)Element).EnableBackButtonOverride)             {                 SetCustomBackButton();             }         }         private void SetCustomBackButton()         {             UIButton btn = new UIButton();             btn.Frame = new CGRect(0, 0, 50, 40);             btn.BackgroundColor = UIColor.Clear;              btn.TouchDown += (sender, e) =>             {                 // Whatever your custom back button click handling                 if (((MyAdvantagePage)Element)?.                 CustomBackButtonAction != null)                 {                     ((MyAdvantagePage)Element)?.                        CustomBackButtonAction.Invoke();                 }             };             NavigationController.NavigationBar.AddSubview(btn);         }     } } 

Android, is tricky. In older versions and future versions of Forms once fixed, you can simply override the OnOptionsItemselected like this

       public override bool OnOptionsItemSelected(IMenuItem item)     {         // check if the current item id          // is equals to the back button id         if (item.ItemId == 16908332)         {             // retrieve the current xamarin forms page instance             var currentpage = (MyAdvantagePage)             Xamarin.Forms.Application.             Current.MainPage.Navigation.             NavigationStack.LastOrDefault();              // check if the page has subscribed to              // the custom back button event             if (currentpage?.CustomBackButtonAction != null)             {                 // invoke the Custom back button action                 currentpage?.CustomBackButtonAction.Invoke();                 // and disable the default back button action                 return false;             }              // if its not subscribed then go ahead              // with the default back button action             return base.OnOptionsItemSelected(item);         }         else         {             // since its not the back button              //click, pass the event to the base             return base.OnOptionsItemSelected(item);         }     } 

However, if you are using FormsAppCompatActivity, then you need to add onto your OnCreate in MainActivity this to set your toolbar:

Android.Support.V7.Widget.Toolbar toolbar = this.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);             SetSupportActionBar(toolbar); 

But wait! If you have too old a version of .Forms or too new version, a bug will come up where toolbar is null. If this happens, the hacked together way I got it to work to make a deadline is like this. In OnCreate in MainActivity:

        MobileApp.Pages.Articles.ArticleDetail.androdAction = () =>         {             Android.Support.V7.Widget.Toolbar toolbar = this.FindViewById<Android.Support.V7.Widget.Toolbar>(Resource.Id.toolbar);             SetSupportActionBar(toolbar);         }; 

ArticleDetail is a Page, and androidAction is an Action that I run on OnAppearing if the Platform is Android on my page. By this point in your app, toolbar will no longer be null.

Couple more steps, the iOS render we made above uses properties that you need to add to whatever page you are making the renderer for. I was making it for my MyAdvantagePage class that I made, which implements ContentPage . So in my MyAdvantagePage class I added

public Action CustomBackButtonAction { get; set; }          public static readonly BindableProperty EnableBackButtonOverrideProperty =                BindableProperty.Create(                nameof(EnableBackButtonOverride),                typeof(bool),                typeof(MyAdvantagePage),                false);          /// <summary>         /// Gets or Sets Custom Back button overriding state         /// </summary>         public bool EnableBackButtonOverride         {             get             {                 return (bool)GetValue(EnableBackButtonOverrideProperty);             }             set             {                 SetValue(EnableBackButtonOverrideProperty, value);             }         } 

Now that that is all done, on any of my MyAdvantagePage I can add this

:    this.EnableBackButtonOverride = true;             this.CustomBackButtonAction = async () =>             {                 if (_browser.CanGoBack)                 {                     _browser.GoBack();                 }                 else                 {                     await Navigation.PopAsync(true);                 }             }; 

That should be everything to get it to work on Android hardware back, and navigation back for both android and iOS.

like image 179
Kyle Avatar answered Oct 04 '22 11:10

Kyle