How to assign an icon to the Navigation Bar for a single page on Android

Pierre-ChristopheDusPierre-ChristopheDus FRUniversity ✭✭✭

Hello,

I try to use an icon instead of the title on the main page of my Xamarin.Forms app.

I've read a lot of related topics, but I didn't found any solution:
navigationpage-settitleicon
navigationpage-settitleicon-works-on-ios-but-not-android
toolbar-title-set-center-align
xamarin-forms-custom-toolbar-android

On iOS this is done easily by adding this on my first page:
NavigationPage.SetTitleIcon(this, "navbar_logo.png");

On Android, I've added this on Toolbar.axml:
<ImageView android:src="@drawable/navbar_adp_logo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" />

This works, but the icon is now visible on each page on Android.

I've tried to use a renderer to hide the icon when I navigate to another page. For this I would like to use the override OnViewAdded() method:

public class CustomNavigationPageRenderer : NavigationPageRenderer { public override void OnViewAdded(Android.Views.View child) { ... } }

But I can't cast the child into Xamarin.Forms.Platform.Android.PageContainer, cause this object is "internal".

So I don't see how I could achieve this...
Would you have any suggestion?

Best Answer

  • Pierre-ChristopheDusPierre-ChristopheDus FR ✭✭✭
    Accepted Answer

    I was given a solution on Stack:

    use OnElementPropertyChanged instead of OnViewAdded:

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);
    
        if (e.PropertyName.Equals("CurrentPage"))
            // If we're on MainPage show the icon, otherwise hide it
            ChangeToolbarIconVisibility(Element.CurrentPage is MainPage); 
    }
    
    private void ChangeToolbarIconVisibility(bool visible) 
    {
        var toolbarIcon = FindViewById<ImageView>(Resource.Id.toolbarIcon);        
        toolbarIcon.Visibility = visible ? Android.Views.ViewStates.Visible : Android.Views.ViewStates.Gone;            
    }
    

    add an id to the ImageView:

    <ImageView android:src="@drawable/navbar_adp_logo" 
               android:layout_width="wrap_content" 
               android:layout_height="wrap_content" 
               android:layout_gravity="center"
               android:id="@+id/toolbarIcon" />
    

Answers

  • Pierre-ChristopheDusPierre-ChristopheDus FRUniversity ✭✭✭

    Some more explanations: I try to use OnViewAdded(Android.Views.View child) cause I've seen that this method is called each time that I navigate in my Xamarin.Forms app.

    I've also noticed that the method is called 2 times during navigation:

    • the first time, the child parameter is a V7.Widget.Toolbar: screenshot1
    • the second time, the child parameter is a Xamarin.Forms.Platform.Android.PageContainer: screenshot2

    With the QuickWatch, I can retrieve the name of the associated page: this would allow me to do the test to hide the icon when I'm on another page.

    But I can't do this in the code:

    PageContainer is inaccessible due to its protection method.

    So I don't know if it's the better approach, but I didn't see another way to do this...

  • Pierre-ChristopheDusPierre-ChristopheDus FRUniversity ✭✭✭
    Accepted Answer

    I was given a solution on Stack:

    use OnElementPropertyChanged instead of OnViewAdded:

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);
    
        if (e.PropertyName.Equals("CurrentPage"))
            // If we're on MainPage show the icon, otherwise hide it
            ChangeToolbarIconVisibility(Element.CurrentPage is MainPage); 
    }
    
    private void ChangeToolbarIconVisibility(bool visible) 
    {
        var toolbarIcon = FindViewById<ImageView>(Resource.Id.toolbarIcon);        
        toolbarIcon.Visibility = visible ? Android.Views.ViewStates.Visible : Android.Views.ViewStates.Gone;            
    }
    

    add an id to the ImageView:

    <ImageView android:src="@drawable/navbar_adp_logo" 
               android:layout_width="wrap_content" 
               android:layout_height="wrap_content" 
               android:layout_gravity="center"
               android:id="@+id/toolbarIcon" />
    
  • lolo_houselolo_house ESMember ✭✭

    I promote another way of doing it much more generic:

    [assembly: Xamarin.Forms.ExportRenderer(typeof(Xamarin.Forms.NavigationPage), typeof(Droid.CustomRenderers.CustomNavigationPageRenderer))]
    namespace Droid.CustomRenderers
    {
    using Xamarin.Forms.Platform.Android.AppCompat;
    using Android.Content;
    using System.ComponentModel;
    using Android.Widget;
    using Xamarin.Forms;

    public class CustomNavigationPageRenderer : NavigationPageRenderer
    {
        public CustomNavigationPageRenderer(Context context) : base(context)
        {
    
        }
    
        protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<NavigationPage> e)
        {
            base.OnElementChanged(e);
    
            SetImageIcon(NavigationPage.GetTitleIcon(Element?.CurrentPage));
        }
    
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
    
            if (e.PropertyName == NavigationPage.TitleIconProperty.PropertyName)
            {
                SetImageIcon(NavigationPage.GetTitleIcon(Element?.CurrentPage));
            }
        }
    
        private async void SetImageIcon(ImageSource val)
        {
            var toolbarIcon = FindViewById<ImageView>(Resource.Id.toolbarIcon);
            toolbarIcon.Visibility = Android.Views.ViewStates.Gone;
            if (val != null)
            {
                var result = await val.LoadDrawableAsync(this.Context); // load ImageSource example
                if (result != null)
                {
                    toolbarIcon.SetImageDrawable(result);
                }
                toolbarIcon.Visibility = val != null ? Android.Views.ViewStates.Visible : Android.Views.ViewStates.Gone;
            }
        }
    }
    

    }

  • pnet1pnet1 USMember ✭✭✭✭
    edited February 2018

    @Pierre-ChristopheDus said:
    I was given a solution on Stack:

    use OnElementPropertyChanged instead of OnViewAdded:

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        base.OnElementPropertyChanged(sender, e);
    
        if (e.PropertyName.Equals("CurrentPage"))
            // If we're on MainPage show the icon, otherwise hide it
            ChangeToolbarIconVisibility(Element.CurrentPage is MainPage); 
    }
    
    private void ChangeToolbarIconVisibility(bool visible) 
    {
        var toolbarIcon = FindViewById<ImageView>(Resource.Id.toolbarIcon);        
        toolbarIcon.Visibility = visible ? Android.Views.ViewStates.Visible : Android.Views.ViewStates.Gone;            
    }
    

    add an id to the ImageView:

    <ImageView android:src="@drawable/navbar_adp_logo" 
               android:layout_width="wrap_content" 
               android:layout_height="wrap_content" 
               android:layout_gravity="center"
               android:id="@+id/toolbarIcon" />
    

    @Pierre-ChristopheDus, where do i put these code? MainActivity? In my case my MainPage inherits from MasterDetailPage and i have two pages Master(ContentPage) and Detail(TabbedPage). I'm not getting to put an image on the BarNavigation. With this code can i?

Sign In or Register to comment.