Hidding NavigationBar in iOS NavigationRenderer

JefimijanaJefimijana USMember ✭✭
edited November 2015 in Xamarin.iOS

Hi,

currently i am working on hidding NavigationBar on iOS Platform. In Shared code I am creating CustomNavigationPage and then call it's Hide() method which implementation is described below.

In Shared code there is:

 public class CustomNavigationPage : NavigationPage
    {    
        public CustomNavigationPage(Page page) : base(page)
        {
            this.Title = page.Title;       
        }   

        public void Hide()
        {
           DependencyService.Get<INavigationBar>().Hide();         
        }
    }

Interface:

    public interface INavigationBar
    {
        void Hide();
    }

And native custom renderer:

[assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomNavigationRenderer))]
[assembly: Xamarin.Forms.Dependency(typeof(CustomNavigationRenderer))]

namespace 
{
    public class CustomNavigationRenderer : NavigationRenderer, INavigationBar
    {
        public CustomNavigationRenderer() { }

        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);
        }

        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            this.NavigationBar.TitleTextAttributes = new UIKit.UIStringAttributes
            {
                //The course title is Open Sans (15px ?, bold, black)
                Font = UIKit.UIFont.FromName("OpenSans-Bold", 15),              
            };

            Color getColor = Color.FromHex("#660044");
            CoreGraphics.CGColor valueColor = new CoreGraphics.CGColor((nfloat)getColor.R, (nfloat)getColor.G, (nfloat)getColor.B, 255);

            this.NavigationBar.BackgroundColor = UIKit.UIColor.FromCGColor(valueColor);

        }

        public void Hide()
        {
           **TODO: None of those below worked in order to hide NavigationBar**

        **Does not work**
            //this.SetNavigationBarHidden(true, false);
            //this.NavigationBarHidden = true;        

        **Does not work**
            //UIKit.UIApplication.SharedApplication.InputViewController.NavigationController.SetNavigationBarHidden(true, false);

        **Does not work**
            //ViewController.NavigationController.SetNavigationBarHidden(true, false); //NavigationController null

        **Does not work**
            //((UIKit.UINavigationController)ViewController).SetNavigationBarHidden(true, false);

        **Does not work**
            //var rootController = this.ViewController;
            //((UIKit.UINavigationController)rootController).SetNavigationBarHidden(true, false);

        **Does not work**
            //UIKit.UINavigationController controller = new UIKit.UINavigationController();
            //controller.SetNavigationBarHidden(true, false);
            //this.AddChildViewController(controller);
            //this.ViewController.AddChildViewController(controller);
        }
    }
}

It looks like NavigationController is null always, even if i am wrapping my ContentPage inside of CustomNavigationPage

ContentPage content = new ContentPage(); CustomNavigationPage course = new CustomNavigationPage(content);

Can someone point me to mistake that i am making or suggest solution for this. I would really appreciate some help.
Thanks.

Tagged:

Best Answers

Answers

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Dependency services are meant to be singletons, but renderers are not. What's happening is that you've registered this type of renderer class as a dependency service, and the first time you ask for an implementation of that service it will just construct a new one. That renderer it gives you is not associated with any actual NavigationPage so it can't really do anything useful.

    Instead of using a dependency service here you should just make a custom NavigationPage subclass and then make a custom renderer subclass for that. It would be something like this (warning: I only typed this, I didn't build it or test it):

    public class MyNavigationPage : NavigationPage
    {
        private bool _navigationBarHidden;
    
        public bool NavigationBarHidden
        {
            get
            {
                return _navigationBarHidden;
            }
    
            set
            {
                if (_navigationBarHidden != value)
                {
                    _navigationBarHidden = value;
                    OnPropertyChanged("NavigationBarHidden");
                }
            }
        }
    }
    
    [assembly: ExportRenderer(typeof(MyNavigationPage), typeof(MyNavigationRenderer))]
    public class MyNavigationRenderer : NavigationRenderer
    {
        protected virtual void OnElementChanged(VisualElementChangedEventArgs e)
        {
            if (e.OldElement != null)
            {
                e.OldElement.PropertyChanged -= OnElementPropertyChanged;
            }
            if (e.NewElement != null)
            {
                e.NewElement.PropertyChanged += OnElementPropertyChanged;
            }
        }
    
        public override void ViewDidLoad()
        {
            UpdateBarVisibility();
        }
    
        private OnElementPropertyChanged(object renderer, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "NavigationBarHidden" && IsViewLoaded)
            {
                UpdateBarVisibility();
            }
        }
    
        private void UpdateBarVisibility()
        {
            NavigationBar.Hidden = ((MyNavigationPage)Element).NavigationBarHidden;
        }
    }
    
  • JefimijanaJefimijana USMember ✭✭

    Hi Adam,

    thank you for your fast answer.

    I did what you said, but it looks like something is still missing since NavigationBar is still visible.

    I am a little bit confused now because my first approach worked on Android Platform, even if i was using DependencyService combined with native NavigationRenderer (as described above).

  • JefimijanaJefimijana USMember ✭✭
    edited December 2015

    Your answer really explained a lot to me.

    Well, if getting myPage as:

    if (e.NewElement != null)
        {
          _page = (NavigationPage)e.NewElement;
          e.NewElement.PropertyChanged += OnElementPropertyChanged; 
        }
    

    was right approach then NavigationPage.SetNavigationBarHidden(_page, false); did not work again :neutral:

  • JefimijanaJefimijana USMember ✭✭
    edited December 2015

    Oh, you were right. It worked!

    I used:

    NavigationPage navpage = new NavigationPage(content);
    NavigationPage.SetHasNavigationBar(content, false);
    

    inside Shared Code, so now NavigationBar is completely hidden on iOS Platform. (it does not work on Android Platform)

    Thank you!

  • alessandrosuppiejalessandrosuppiej ITMember ✭✭

    Hi @adamkemp , forgive me. i am not able to get it running.
    i always see the navigation bar on iOS.

    My goal is this : i have to satisfy my boss' request. He wants the same appearance in android and ios.
    I do like android behavior. i'd like to have in ios...the same masterdetail page as android :
    On the first row the action bar and under it... all the contents.

    I want to remove iOS action bar because i am not able to render it like android version.
    So please can you tell me a way to put the same things on ios and android navigation bar ?

    sorry for my english

  • alessandrosuppiejalessandrosuppiej ITMember ✭✭

    @adamkemp . yesterday i updated my version of xf to 2.x because i needed to use ScrollView.ScrollX poperty.
    Today i started a new project with master/detail page.
    In older versions of xf , contentpage in ios cover the entire screen.
    Today the application has a fixed toolbar like native android applications. Am i going crazy or is it a known behavior ?
    Thanks in advance for your patience.

    Alessandro

Sign In or Register to comment.