Changing the Nav- & Status Bar appearance dynamically

JonasRembrattJonasRembratt SEUniversity ✭✭✭
edited June 12 in Xamarin.iOS

The app we're writing a.t.m. contains both dark and light pages. We rely mainly on stack navigation and so a NavigationPage is in use. Most pages should display the Navigation Bar but there are exceptions.

Now, I have not managed to crack how to ensure a proper Status Bar behavior. I have tried to rely on the default behavior (setting the info.plist UIViewControllerBasedStatusBarAppearance = false) but that produces som weird behavior related to modal pages and landsape mode.
When I push a modal page the status bar appearance isn't affected (if already white text it remains white on a white modal page background, or the other way around).

This behavior goes away if I set the UIViewControllerBasedStatusBarAppearance = true to take control of the status bar. I don't even have to override the PreferredStatusBarStyle method in a custom NavigationRenderer.

Question 1:
Is the behavior I'm seeing (with a non-adjusting statusbar on modal pages) a bug in iOS or in Xamarin Forms?

When writing a custom renderer (based on this code) I can achieve a transparent (Apple "translucent") navigation bar which then automatically yields a status bar with the correct style (light when background is dark or the other way around). The problem is I can't figure out how to set a "normal" navigation bar for individual pages; once I've made the nav-bar transparent I can't make it opaque (or "translucent").

I run this code in the custom renderer's overridden ViewDidLoad to produce the transparent navigation bar ...

UINavigationBar.Appearance.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
UINavigationBar.Appearance.ShadowImage = new UIImage();
UINavigationBar.Appearance.BackgroundColor = UIColor.Clear;
UINavigationBar.Appearance.TintColor = getTextColor().ToUIColor(); 
UINavigationBar.Appearance.BarTintColor = UIColor.Clear;
UINavigationBar.Appearance.Translucent = true;
UINavigationBar.Appearance.BarStyle = UIBarStyle.Black;

... which does the trick. But running the same code again with different values (when pushing new pages) have no effect.

Question 2:
Is it not possible to affect the navigation bar appearance dynamically? If it is; what am I doing wrong?

Answers

  • LucasZhangLucasZhang Member, Xamarin Team Xamurai

    NavigationPage in Forms sometimes will have conflict with NavigationBar in iOS . I don't think this is a bug in native iOS .
    And if you want to set the style of navigation , you can set a custom View as Navigation Bar .

    in Custom Renderer

    using Foundation;
    using UIKit;
    using Xamarin.Forms.Platform.iOS;
    using Xamarin.Forms;
    using xxx.iOS;
    using CoreGraphics;
    using xxx;
    using ObjCRuntime;
    [assembly: ExportRenderer(typeof(ContentPage), typeof(MyPageRenderer))]
    namespace xxx.iOS
    {
        public class MyPageRenderer: PageRenderer
        {
            public override void ViewWillAppear(bool animated)
            {
                base.ViewWillAppear(animated);
    
                var page = Element as ContentPage;
    
                NavigationController.NavigationBar.Hidden = true;
    
    
                double height = IsiphoneX();
    
                UIView backView = new UIView()
                {
                    BackgroundColor = UIColor.White,
                    Frame = new CGRect(0,20,UIScreen.MainScreen.Bounds.Width, height),
    
                };
    
    
                UIButton backBtn = new UIButton() {
    
                    Frame = new CGRect(20, height-44, 40, 44),
                    Font = UIFont.SystemFontOfSize(18),
    
                } ;
                backBtn.SetTitle("Back", UIControlState.Normal);
                backBtn.SetTitleColor(UIColor.Blue, UIControlState.Normal);
                backBtn.AddTarget(this,new Selector("GoBack"),UIControlEvent.TouchUpInside);
    
                UILabel titleLabel = new UILabel() {
                    Frame=new CGRect(UIScreen.MainScreen.Bounds.Width/2-75, 0,150, height),
                    Font = UIFont.SystemFontOfSize(20),
                    Text = page.Title,
                    TextColor = UIColor.Black,
                    Lines = 0,
    
                };
    
                UILabel line = new UILabel() {
    
                    Frame = new CGRect(0, height, UIScreen.MainScreen.Bounds.Width, 0.5),
                    BackgroundColor = UIColor.Black,
    
                };
    
                backView.AddSubview(backBtn);
                backView.AddSubview(titleLabel);
                backView.AddSubview(line);
    
                View.AddSubview(backView);
            }
    
    
             double IsiphoneX()
            {
    
                double height = 44;
    
                if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
                {
                    if (UIApplication.SharedApplication.Delegate.GetWindow().SafeAreaInsets.Bottom > 0.0)
                    {
                        height = 64;
                    }
                }
    
                return height;
            }
    
            [Export("GoBack")]
            void GoBack()
            {
                NavigationController.PopViewController(true);
            }
    
            public override void ViewWillDisappear(bool animated)
            {
                base.ViewWillDisappear(animated);
    
                NavigationController.NavigationBar.Hidden = false;
            }
    
        }
    }
    
  • JonasRembrattJonasRembratt SEUniversity ✭✭✭
    edited June 13

    Thanks Lucas.

    My problem isn't really with how to customize the navigation bar itself but with how the status bar appears and behaves. if I go "full automatic" (setting UIViewControllerBasedStatusBarAppearance = false) I get som buggy behavior such as the status bar appearing in landscape in certain scenarios. Might be this is the XF/iOS conflict you're talking about? If I take control (setting UIViewControllerBasedStatusBarAppearance = true and write custom renderers) this behavior goes away (even without a custom renderer) but I run into problems with the root page, which shouldn't present the navigation bar. Just hiding the navbar makes me loose control of the status bar which then goes Default (black). If I instead makes the navbar transparent (as per the code in the OP) I can't restore it in child pages.

    So, no matter what I do I get some undesireable behavior. I must be missing something ...

  • LucasZhangLucasZhang Member, Xamarin Team Xamurai

    UIViewControllerBasedStatusBarAppearance specifies whether the status bar appearance is based on the style preferred by the view controller that is currently under the status bar. When this key is not present or its value is set to True, the view controller determines the status bar style. When the key is set to False, view controllers (or the app) must each set the status bar style explicitly using the UIApplication object.

  • JonasRembrattJonasRembratt SEUniversity ✭✭✭

    Sounds like I have misunderstood the documentation. But what's the difference betwen the view controller determines the status bar style ... and ... view controllers (or the app) must each set the status bar style explicitly using the UIApplication object? When I set that flag the view controllers' PreferredStatusBarStyle gets called (otherwise not).

Sign In or Register to comment.