How to change navigation page back button in xamarin forms

12,022

Solution 1

If your MainActivity is FormsApplicationActivity, you could refer to this example :

https://github.com/jessejiang0214/ChangeBackIconInXF/tree/master/Droid

If your MainActivity type is FormsAppCompatActivity, you could custom a PageRenderer and change the Toolbar's NavigationIcon.

For example :

[assembly: ExportRenderer(typeof(ContentPage), typeof(NavigationPageRendererDroid))]
...
public class NavigationPageRendererDroid : PageRenderer
{
    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Page> e)
    {
        base.OnElementChanged(e);

        var context = (Activity)Xamarin.Forms.Forms.Context;
        var toolbar = context.FindViewById<Android.Support.V7.Widget.Toolbar>(Droid.Resource.Id.toolbar);

        toolbar.NavigationIcon = Android.Support.V4.Content.ContextCompat.GetDrawable(context, Resource.Drawable.Back);
    }
}

Usage :

MainPage = new NavigationPage(new MainPage());
...
//When click a button in MainPage, navigate to another page
private async void Button_Clicked(object sender, EventArgs e)
{
    await Navigation.PushAsync(new TestPage());
}

Effect.


Update :

When you use Navigation.PushAsync() method navigate to another page, the system will automatically update the Toolbar's icon, you could find in the source code :

protected virtual Task<bool> OnPushAsync(Page view, bool animated)
{
    return SwitchContentAsync(view, animated);
}

Task<bool> SwitchContentAsync(Page page, bool animated, bool removed = false, bool popToRoot = false)
{
    ...
    UpdateToolbar();
    ...
}

void UpdateToolbar()
{
    ...
    bool isNavigated = ((INavigationPageController)Element).StackDepth > 1;
    if (isNavigated)
    {
        ...
        if (NavigationPage.GetHasBackButton(Element.CurrentPage))
        {
             //Set the navigation back  icon < =================== !!! =-=
             var icon = new DrawerArrowDrawable(activity.SupportActionBar.ThemedContext);
             icon.Progress = 1;
             bar.NavigationIcon = icon;
        }
    }
    ...
}

Solution :

So we have no choice but to custom a NavigationPageRenderer, override the OnPushAsync method to set the Toolbar's icon.

using AToolbar = Android.Support.V7.Widget.Toolbar;
[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(NavigationPageRendererDroid))] // APPCOMP
...
public class NavigationPageRendererDroid : Xamarin.Forms.Platform.Android.AppCompat.NavigationPageRenderer // APPCOMP
{
    public AToolbar toolbar;
    public Activity context;

    protected override Task<bool> OnPushAsync(Page view, bool animated)
    {
        var retVal = base.OnPushAsync(view, animated);

        context = (Activity)Xamarin.Forms.Forms.Context;
        toolbar = context.FindViewById<Android.Support.V7.Widget.Toolbar>(Droid.Resource.Id.toolbar);

        if (toolbar != null)
        {
            if (toolbar.NavigationIcon != null)
            {
                toolbar.NavigationIcon = Android.Support.V4.Content.ContextCompat.GetDrawable(context, Resource.Drawable.Back);
                //toolbar.SetNavigationIcon(Resource.Drawable.Back);
            }
        }
        return retVal;
    }
}

The CustomNavigationPage are defined in PCL :

public class CustomNavigationPage : NavigationPage
{
    public CustomNavigationPage(Page startupPage) : base(startupPage)
    {
    }
}

Usage :

public App()
{
    InitializeComponent();

    MainPage = new CustomNavigationPage(new MainPage());
}
...
// In MainPage
private async void Button_Clicked(object sender, EventArgs e)
{
    await Navigation.PushAsync(new TestPage());
}

Solution 2

I solved this the next way: In my MainActivity i am added static toolbar property and identified it in OnCreateOptionsMenu

    public static Toolbar ToolBar { get; private set; }

    public override bool OnCreateOptionsMenu(IMenu menu)
    {
        ToolBar = FindViewById<Toolbar>(Resource.Id.toolbar);
        ToolBar.SetNavigationIcon(Resource.Drawable.arrow);
        return base.OnCreateOptionsMenu(menu);
    }

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

Then in PageRenderer:

protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
     base.OnElementChanged(e);
     MainActivity.ToolBar?.SetNavigationIcon(Resource.Drawable.arrow);
}

But!! From 2 ways i have bad effect with redrawing

Usage:

async void tapImage_Tapped(object sender, EventArgs e)
{
     await Navigation.PushAsync(new ChooseGenrePage(_listGenres));
}
Share:
12,022

Related videos on Youtube

Bogdan Sevryukov
Author by

Bogdan Sevryukov

Updated on June 04, 2022

Comments

  • Bogdan Sevryukov
    Bogdan Sevryukov almost 2 years

    I am trying to change back arrow image in navigation page. For this in android app i created navigation page renderer and then using method toolbar.SetNavigationIcon and its not working, but when i use toolbar.SetLogo its working fine.

        protected override void OnElementChanged(ElementChangedEventArgs<NavigationPage> e)
        {
    
            base.OnElementChanged(e);
            toolbar.SetNavigationIcon(Resource.Drawable.arrow); 
            toolbar.SetLogo(Resource.Drawable.arrow);
        }
        public override void OnViewAdded(Android.Views.View child)
        {
            base.OnViewAdded(child);
            if (child.GetType() == typeof(Android.Support.V7.Widget.Toolbar))
            {
                toolbar = (Android.Support.V7.Widget.Toolbar)child;
                toolbar.ChildViewAdded += Toolbar_ChildViewAdded;
            }
        }
    

    I also tried add image to app:navigationIcon in toolbar.axml, and it shows great in designer my arrow

    But, when i starting my app i have the same standart arrow icon enter image description here

    • Bogdan Sevryukov
      Bogdan Sevryukov over 6 years
      no, it did not help
    • York Shen
      York Shen over 6 years
      What is your MainActivity type ?
  • Bogdan Sevryukov
    Bogdan Sevryukov over 6 years
    check my answer please
  • York Shen
    York Shen over 6 years
    @BogdanSevryukov, I have update my answer, it works perfect, you could check it.
  • York Shen
    York Shen over 6 years
    I have update my answer to solve this redrawing issue, hope this can help you. : )
  • Bogdan Sevryukov
    Bogdan Sevryukov over 6 years
    I`am using now BoxView from this examle link It allows me to easily change height, icons, font-family background gradient for all content page with header :) Thank you for your answer :) it will help me in the future 100%