How to control Status Bar text color

JonasRembrattJonasRembratt ✭✭✭SEUniversity ✭✭✭

In the app we're currently building there is a need to set, on a page level, the color of the navigation bar text and of the status bar elements (operator, battery level etc.). The navigation bar text color should be set to a blue color and, as the status bar elements cannot be colored in iOS, need to be black. The problem is this is not something we can set from the info.plist file, or at app start, since it needs to change depending on the currently presented page.

Example:
Start page (a menu). No nav bar at all; status bar elements needs to be white (the background is dark)
Other (sub) page: Blue navigation bar text color and black status bar elements (the sub page background is very bright)

After iOS 9 the UIApplication.SetStatusBarStyle(); API was deprecated. As I understand it this leaves me with having to write a custom renderer for NavigationPage and override PreferredStatusBarStyle(). So, first question: Is that correct or is there still a different way to control the status bar element style?

This is my attempt at doing this (a custom renderer).

[assembly: ExportRenderer(typeof(NavigationPage), typeof(NavigationPageRenderer))]

namespace QuTIP.iOS.Renderers
{

    public class NavigationPageRenderer : NavigationRenderer
    {
        private NavigationPage _navigationPage;

        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);
            _navigationPage = Element as NavigationPage;
            if (_navigationPage != null)
            {
                wireNavigationPage();
            }
        }

        private void wireNavigationPage()
        {
            _navigationPage.ChildAdded += onChildAdded;
            _navigationPage.Popped += onPopped;
            // todo unwire when page gets disposed
        }

        private void onPopped(object sender, NavigationEventArgs e) => invalidateStatusBar();

        private void onChildAdded(object sender, ElementEventArgs e) => invalidateStatusBar();

        private void invalidateStatusBar()
        {
            BeginInvokeOnMainThread(() => SetNeedsStatusBarAppearanceUpdate());
        }

        public override UIStatusBarStyle PreferredStatusBarStyle() // <-- NEVER CALLED!
        {
            var page = (Page)Element;

            // note: StatusBar is one of my custom utility classes
            if (StatusBar.TryGetNavigationBarBackgroundColor(out var backgroundColor, page)) 
            {
                return backgroundColor.Luminosity < .5
                    ? UIStatusBarStyle.LightContent
                    : UIStatusBarStyle.BlackOpaque;
            }

            return base.PreferredStatusBarStyle();
        }
    }
}

This fails. The PreferredStatusBarStyle() method never gets called.

I have googled this problem quite a bit and just to get the typical questions out of the way: Yes, the UIViewControllerBasedStatusBarAppearance key in infp.plist has been set to NO (false). (That, btw, doesn't make much sense to me; answering the question "should individual controllers control status bar appearance" with "NO" when that is precisely what you want).

Also, the way we set the "status bar text color" (setting the NavigationPage.BarTextColor) seems a bit strangely implemented IMHO. Setting it does effect both the navigation bar text color and the status bar element color but leaves no control. If I simply set the navigation bar text color to blue the status element style gets set to "light", for some reason. If I'm content with always using black or white for the navigation bar text color then all is good but that's very limiting.

Tagged:

Best Answer

Answers

  • JonasRembrattJonasRembratt ✭✭✭ SEUniversity ✭✭✭

    Flipping UIViewControllerBasedStatusBarAppearance to true made iOS start calling PreferredStatusBarStyle, which makes perfect sense. However, as I keep returning BlackTranslucent I still get white status elements. Could there be some other automatic management of the coloring of these elements going on I might not be aware of?

  • JonasRembrattJonasRembratt ✭✭✭ SEUniversity ✭✭✭
    edited May 23

    Never mind the last post. I just didn't realize that BlackTranslucent is actually a deprecated value, meaning "light content" (apparently). Setting the proper value gives me the correct behavior.

    What I still struggle to understand is why I still get black status element even though I set light content in the info.plist (and don't contradict it in the custom renderer). The problem is the first page (stack navigation), a menu, where I'd need light content. The custom renderer's overridden PreferredStatusBarStyle() never gets called for the first (menu) page or when I pop back to it. When popping; the popped page's overridden PreferredStatusBarStyle() gets called (which is pretty pointless) but not the page being popped back to. Also, calling SetNeedsStatusBarAppearanceUpdate() has no apparent effect.

  • ColeXColeX Xamurai Member, Xamarin Team Xamurai
    edited May 24

    It tells us override the method in UIViewController ..

    And according to my test , only UIStatusBarStyle.Default shows black text , the other three options shows white text.

Sign In or Register to comment.