3
votes

Before iOS 13 I could change the status bar colour using the following bit of code:

        UIView statusBar = UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) as UIView;
        if (statusBar.RespondsToSelector(new ObjCRuntime.Selector("setBackgroundColor:")))
        {
            statusBar.BackgroundColor = UIColor.Clear.FromHex(0x323232);
            statusBar.TintColor = UIColor.White;
            app.StatusBarStyle = UIStatusBarStyle.BlackOpaque;
        }

However, on iOS13 I get the following runtime error

Objective-C exception thrown. Name: NSInternalInconsistencyException Reason: App called -statusBar or -statusBarWindow on UIApplication: this code must be changed as there's no longer a status bar or status bar window. Use the statusBarManager object on the window scene instead.

Any idea on how to change the status bar on iOS13?

EDIT: Just to point out, this is for Xamarin and not for Swift. To clarify the duplicate marker.

3
@Mac How is this a duplicate? That is for swift, this is for XamarinDavid Pilkington
It's not duplicate .And here need a solution for xamarin ios . It seems like need a new way about setting background color of status bar . However , from apple document , there is no more detail about how to use UIStatusBarManager.Junior Jiang
Error is the same, and the solution should be the same, you just have to convert the swift code to C# Xamarin code. That said, I did a quick test and KeyWindow is always nuil, so the answers from that dupe post fail.jgoldberger - MSFT
@jgoldberger-MSFT saying that the solution is the same just because the error is the same seems a little bit of an over simplification given the 2 frameworks at play here.David Pilkington

3 Answers

7
votes

From error , you need to use UIStatusBarManager in IOS 13.

If you have updated VS to the latest version(Visual Studio 2019 version 16.3.0/Visual Studio 2019 for Mac version 8.3 above), you can change color as follow:

UIView statusBar = new UIView(UIApplication.SharedApplication.KeyWindow.WindowScene.StatusBarManager.StatusBarFrame);
statusBar.BackgroundColor = UIColor.Yellow;
UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);

Else the follow methods can make it works .

UIView statusBar = new UIView(UIApplication.SharedApplication.StatusBarFrame);
statusBar.BackgroundColor = UIColor.Yellow;
UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);

If the view is not fully rendered , UIApplication.SharedApplication.KeyWindow will return null .So you can change status bar color after fully rendered . Here is the sample .

===================================Update=================================

If in Forms project , you can have a try with invoking method in AppDelegate.cs

public override void OnActivated(UIApplication uiApplication)
{
    if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
    {
        // If VS has updated to the latest version , you can use StatusBarManager , else use the first line code
        // UIView statusBar = new UIView(UIApplication.SharedApplication.StatusBarFrame);
        UIView statusBar = new UIView(UIApplication.SharedApplication.KeyWindow.WindowScene.StatusBarManager.StatusBarFrame);
        statusBar.BackgroundColor = UIColor.Red;
        UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);
    }
    else
    {
        UIView statusBar = UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) as UIView;
        if (statusBar.RespondsToSelector(new ObjCRuntime.Selector("setBackgroundColor:")))
        {
            statusBar.BackgroundColor = UIColor.Red;
            UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.BlackOpaque;
        }
    }
    base.OnActivated(uiApplication);
} 

Note :

Not sure this solurion will always work in AppDelegate.cs, better invoked in Controller.cs's method , because from iOS 13 , Apple have modified the architure of AppDelegate and added SceneDelegate to project.

0
votes

This also works, if used in ViewDidAppear override in a UIViewController. I previously tested in ViewWillAppear and even that was too soon to have a KeyWindow non-null:

public override void ViewDidAppear(bool animated)
{
    base.ViewDidAppear(animated);
    if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
    {
        //Obj-C: 
        // UIView *statusBar = [[UIView alloc]initWithFrame:[UIApplication sharedApplication].keyWindow.windowScene.statusBarManager.statusBarFrame] ;
        // statusBar.backgroundColor = [UIColor redColor];
        // [[UIApplication sharedApplication].keyWindow addSubview:statusBar];

        // Xamarin.iOS: 
        UIView statusBar = new UIView(UIApplication.SharedApplication.KeyWindow.WindowScene.StatusBarManager.StatusBarFrame);
        statusBar.BackgroundColor = UIColor.Red;
        UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);
    }
    else
    {
        UIView statusBar = UIApplication.SharedApplication.ValueForKey(new NSString("statusBar")) as UIView;
        if (statusBar.RespondsToSelector(new ObjCRuntime.Selector("setBackgroundColor:")))
        {
            statusBar.BackgroundColor = UIColor.Red;
            statusBar.TintColor = UIColor.White;
            UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.BlackOpaque;
        }
    }
}

And that is the same solution provided in the duplicate question: https://stackoverflow.com/a/58028658/2913599

-1
votes

Could you please try the below solution. it works fine for me in the same scenario

if (@available(iOS 13.0, *)) {            
            UIView *statusBar = [[UIView alloc]initWithFrame:[UIApplication sharedApplication].keyWindow.windowScene.statusBarManager.statusBarFrame];
            statusBar.backgroundColor = [UIColor redColor];
            [[UIApplication sharedApplication].keyWindow addSubview:statusBar];

        } else {
            // Fallback on earlier versions
            UIView *statusBar=[[UIApplication sharedApplication] valueForKey:@"statusBar"];
            statusBar.backgroundColor = [UIColor redColor];
            [statusBar setNeedsDisplay];
        }