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.
Add following key value in info.plist.
<key>UIViewControllerBasedStatusBarAppearance</key> <true/> <key>UIStatusBarStyle</key> <string>UIStatusBarStyleBlackOpaque</string>
Change style in PageRenderer.
[assembly: ExportRenderer(typeof(Page), typeof(MyRenderer))] namespace FormsApp.iOS { class MyRenderer : PageRenderer { public override UIStatusBarStyle PreferredStatusBarStyle() { //return UIStatusBarStyle.Default; //Black text return UIStatusBarStyle.LightContent; //White text } } }
Answers
Add following key value in info.plist.
Change style in PageRenderer.
Flipping
UIViewControllerBasedStatusBarAppearance
totrue
made iOS start callingPreferredStatusBarStyle
, which makes perfect sense. However, as I keep returningBlackTranslucent
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?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 overriddenPreferredStatusBarStyle()
gets called (which is pretty pointless) but not the page being popped back to. Also, callingSetNeedsStatusBarAppearanceUpdate()
has no apparent effect.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.