Toolbar missing on navigation using Navigation.Pushasync in iOS

paul_macpaul_mac Member ✭✭✭
edited February 28 in Xamarin.Forms

I have a Xamarin Forms bottom tabbed page with three tabs. In one of those tabs, I navigate within the tab to another content page (say Navpage); In this navigated page (Navpage), I can't see the toolbar (image in titleview) in iOS set like below in the custom NavigationRenderer subclass
NavigationBar.TopItem.TitleView = image; //UIImageView
But I can see the toolbar in android( the toolbar set in main activity as Toolbar resource). I have disabled the back button in XAML. Why ? I need a fix for iOS.
NOTE: I am navigating from the tab to other content page (Navpage) like this:
Navigation.PushAsync(new NavPage(parameter));
If I navigate like Navigation.PushAsync(new NavigationPage(new NavPage(parameter))), I get the toolbar image overflowed in the second row below the navbar's place, where the first row (actual place of navbar) has only the "<Back" button on the top left corner, in this way, in android I get the toolbar resource image twice in first and second row at the place of navbar

Best Answers

  • LandLuLandLu Xamurai
    Accepted Answer

    iOS is different from Android, it has its own features for Navigation Controller.
    Each UIViewController has its own NavigationItem, they are independent of each other. NavigationBar.TopItem only means the first one of the navigation items which has been put in the navigation stack.
    If you want to set the same style for the TitleView of every UIViewController in a particular navigation stack. You should create a custom content page, make all the pages which you want to use the same title view inherit from that custom base content page. At last, create a pagerenderer for that customized content page in the iOS project. Set the title view there.

    // Make all your pages inherit from the base page
    public partial class BaseContentPage : ContentPage
    {
        public BaseContentPage ()
        {
            InitializeComponent ();
        }
    }
    
    // Create a custom renderer for that page   
    [assembly: ExportRenderer(typeof(BaseContentPage), typeof(MyContentPageRenderer))]
    namespace Demo.iOS
    {
        public class MyContentPageRenderer : PageRenderer
        {
            public override void ViewWillAppear(bool animated)
            {
                base.ViewWillAppear(animated);
    
                // ...
                NavigationController.TopViewController.NavigationItem.TitleView = image; //UIImageView
            }
        }
    }
    
  • paul_macpaul_mac ✭✭✭
    edited March 1 Accepted Answer

    I finally settled with this code, without a base content page as I had only one content page of that kind:

    //Gave the name of my Content page (Navpage) here in the ExportRenderer itself
    [assembly: ExportRenderer(typeof(NavPage), typeof(ContentPageRenderer))]
    namespace MyNamespace.iOS.Renderers
    {
        class ContentPageRenderer : PageRenderer
        {
            public override void ViewWillAppear(bool animated)
            {
                base.ViewWillAppear(animated);
                var image = new UIImageView(UIImage.FromFile("myimage.png").ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal));
                NavigationController.TopViewController.NavigationItem.TitleView = image; //UIImageView
            }
        }
    }
    

    Thanks very much @LandLu !

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai
    Accepted Answer

    iOS is different from Android, it has its own features for Navigation Controller.
    Each UIViewController has its own NavigationItem, they are independent of each other. NavigationBar.TopItem only means the first one of the navigation items which has been put in the navigation stack.
    If you want to set the same style for the TitleView of every UIViewController in a particular navigation stack. You should create a custom content page, make all the pages which you want to use the same title view inherit from that custom base content page. At last, create a pagerenderer for that customized content page in the iOS project. Set the title view there.

    // Make all your pages inherit from the base page
    public partial class BaseContentPage : ContentPage
    {
        public BaseContentPage ()
        {
            InitializeComponent ();
        }
    }
    
    // Create a custom renderer for that page   
    [assembly: ExportRenderer(typeof(BaseContentPage), typeof(MyContentPageRenderer))]
    namespace Demo.iOS
    {
        public class MyContentPageRenderer : PageRenderer
        {
            public override void ViewWillAppear(bool animated)
            {
                base.ViewWillAppear(animated);
    
                // ...
                NavigationController.TopViewController.NavigationItem.TitleView = image; //UIImageView
            }
        }
    }
    
  • paul_macpaul_mac Member ✭✭✭
    edited March 1

    @LandLu, thanks for your answer, very informative - crisp and clear

    Actually, in the meantime, I set the toolbar in the navpage's constructor for only ios platform like this

    public partial class NavPage : ContentPage
    {
        public NavPage()
    {
        InitializeComponent();
        if (Device.RuntimePlatform == Device.iOS)
        {
                            var myToolbarItem = new ToolbarItem()
                            {
                                Icon = "myimage.png",
                            };
                            ToolbarItems.Insert(0, myToolbarItem);
        }
    }
    }
    

    I got the image in my navigated page (navpage), but the image is in blue tint color (default tint color in ios), dont know how to render it originally (searched the internet, there are only solutions to set as a particular color - but the image has two different colors), please let me know if you know how to override it.

    Or do you think I should follow your method of using a custom page renderer, you please suggest...
    NOTE: I have only one page like this, I dont need this fix in any other pages of my app
    Thanks again

  • LandLuLandLu Member, Xamarin Team Xamurai

    @paul_mac Yes, the default tint color for navigation item is blue. And we have to use custom renderer for changing the default behavior.
    The toolbar item is rendered as left navigation item on the iOS project. So I think you could try the code below to handle it:

    public override void ViewWillAppear(bool animated)
    {
        base.ViewWillAppear(animated);
    
        var toolbarItem = (Element as ContentPage).ToolbarItems.FirstOrDefault();
        if (toolbarItem != null)
        {
            var icon = toolbarItem.Icon.File;
    
            // In this way the image will be rendered as its original appearance
            var navigationItem = new UIBarButtonItem(UIImage.FromBundle(icon).ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal), UIBarButtonItemStyle.Plain, 
                                                    (sender, args) => 
                                                    { 
                                                        // Add the event again 
                                                    });
            NavigationController.TopViewController.NavigationItem.SetRightBarButtonItem(navigationItem, false);
        }
    
    }
    
  • paul_macpaul_mac Member ✭✭✭
    edited March 1 Accepted Answer

    I finally settled with this code, without a base content page as I had only one content page of that kind:

    //Gave the name of my Content page (Navpage) here in the ExportRenderer itself
    [assembly: ExportRenderer(typeof(NavPage), typeof(ContentPageRenderer))]
    namespace MyNamespace.iOS.Renderers
    {
        class ContentPageRenderer : PageRenderer
        {
            public override void ViewWillAppear(bool animated)
            {
                base.ViewWillAppear(animated);
                var image = new UIImageView(UIImage.FromFile("myimage.png").ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal));
                NavigationController.TopViewController.NavigationItem.TitleView = image; //UIImageView
            }
        }
    }
    

    Thanks very much @LandLu !

Sign In or Register to comment.