How to change the status bar background color and text color on iOS 13?

IosSwiftStatusbarIos13

Ios Problem Overview


With the arrival of iOS 13 statusBar's view is no longer accessible trough:

value(forKey: "statusBar") as? UIView

Due to:

> Terminating app due to uncaught exception > '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.'

But it's not clear how it should be used for changing colours as keyWindow?.windowScene?.statusBarManager does not appear to contain anything related to it.

*I'm compiling my code with (iOS 10, ) compatibility, so I intend to continue using UIKit.

Any ideas regarding this subject?

Ios Solutions


Solution 1 - Ios

You can add some conditions or use first one. Just create some extension for UIApplication.

extension UIApplication {
var statusBarUIView: UIView? {
    if #available(iOS 13.0, *) {
        let tag = 38482
        let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
        
        if let statusBar = keyWindow?.viewWithTag(tag) {
            return statusBar
        } else {
            guard let statusBarFrame = keyWindow?.windowScene?.statusBarManager?.statusBarFrame else { return nil }
            let statusBarView = UIView(frame: statusBarFrame)
            statusBarView.tag = tag
            keyWindow?.addSubview(statusBarView)
            return statusBarView
        }
    } else if responds(to: Selector(("statusBar"))) {
        return value(forKey: "statusBar") as? UIView
    } else {
        return nil
    }
  }
}

UPDATED: Sorry, I don't have enough time to test it in real projects, but it works in "Hello world" app. You can read more info about keyWindow and statusBarFrame in order to make it better.

extension UIApplication {
var statusBarUIView: UIView? {
    
    if #available(iOS 13.0, *) {
        let tag = 3848245
        
        let keyWindow = UIApplication.shared.connectedScenes
            .map({$0 as? UIWindowScene})
            .compactMap({$0})
            .first?.windows.first
        
        if let statusBar = keyWindow?.viewWithTag(tag) {
            return statusBar
        } else {
            let height = keyWindow?.windowScene?.statusBarManager?.statusBarFrame ?? .zero
            let statusBarView = UIView(frame: height)
            statusBarView.tag = tag
            statusBarView.layer.zPosition = 999999
            
            keyWindow?.addSubview(statusBarView)
            return statusBarView
        }
        
    } else {
        
        if responds(to: Selector(("statusBar"))) {
            return value(forKey: "statusBar") as? UIView
        }
    }
    return nil
  }
}

Solution 2 - Ios

Unfortunately Apple deprecated some of the mentioned methods of accessing the status bar and editing its attributes. You will have to use the StatusBarManager object of the WindowScene. The following method works for iOS 13 and above:

extension UINavigationController {

    func setStatusBar(backgroundColor: UIColor) {
        let statusBarFrame: CGRect
        if #available(iOS 13.0, *) {
            statusBarFrame = view.window?.windowScene?.statusBarManager?.statusBarFrame ?? CGRect.zero
        } else {
            statusBarFrame = UIApplication.shared.statusBarFrame
        }
        let statusBarView = UIView(frame: statusBarFrame)
        statusBarView.backgroundColor = backgroundColor
        view.addSubview(statusBarView)
    }

}

Solution 3 - Ios

I have encountered this issue before. My application got crash while I run this code using XCode 11 and Swift 5.0.

Previous Code:-

UIApplication.shared.statusBarView?.backgroundColor = UIColor.init(red: 243/250, green: 243/250, blue: 243/250, alpha: 1)
    

Just Changed to:-

if #available(iOS 13.0, *) {
    let statusBar = UIView(frame: UIApplication.shared.keyWindow?.windowScene?.statusBarManager?.statusBarFrame ?? CGRect.zero)
     statusBar.backgroundColor = UIColor.init(red: 243/250, green: 243/250, blue: 243/250, alpha: 1)
     UIApplication.shared.keyWindow?.addSubview(statusBar)
} else {
     UIApplication.shared.statusBarView?.backgroundColor = UIColor.init(red: 243/250, green: 243/250, blue: 243/250, alpha: 1)
}

Now my problem solved. Happy coding.

Solution 4 - Ios

for swift 5.0 I've done this to change background color,

    if #available(iOS 13.0, *) {
           let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first 
           // Reference - https://stackoverflow.com/a/57899013/7316675
           let statusBar = UIView(frame: window?.windowScene?.statusBarManager?.statusBarFrame ?? CGRect.zero)
           statusBar.backgroundColor = .white
           window?.addSubview(statusBar)
    } else {
           UIApplication.shared.statusBarView?.backgroundColor = .white
           UIApplication.shared.statusBarStyle = .lightContent
    }

https://medium.com/@trivediniki94/surprises-after-upgrading-to-xcode-11-ios-13-b52b36e05fa8

Solution 5 - Ios

This worked for me in Swift 5

   override func viewDidLoad() {
      super.viewDidLoad()

      if #available(iOS 13, *)
      {
          let statusBar = UIView(frame: (UIApplication.shared.keyWindow?.windowScene?.statusBarManager?.statusBarFrame)!)
          statusBar.backgroundColor = #colorLiteral(red: 0.2346, green: 0.3456, blue: 0.5677, alpha: 1)
          UIApplication.shared.keyWindow?.addSubview(statusBar)
      } else {
         // ADD THE STATUS BAR AND SET A CUSTOM COLOR
         let statusBar: UIView = UIApplication.shared.value(forKey: "statusBar") as! UIView
         if statusBar.responds(to:#selector(setter: UIView.backgroundColor)) {
            statusBar.backgroundColor = #colorLiteral(red: 0.2346, green: 0.3456, blue: 0.5677, alpha: 1)
         }
         UIApplication.shared.statusBarStyle = .lightContent
      }
   }

Solution 6 - Ios

Use the following code:

if (@available(iOS 13, *)) {
    let statusBar1 =  UIView()
    statusBar1.frame = UIApplication.shared.statusBarFrame
    statusBar1.backgroundColor = UIColor.red
    UIApplication.shared.keyWindow?.addSubview(statusBar1)
}

to achieve this result:

enter image description here

Solution 7 - Ios

Tested and 100% worked for me

func statusBarColorChange(){

    if #available(iOS 13.0, *) {
            
            let statusBar = UIView(frame: UIApplication.shared.keyWindow?.windowScene?.statusBarManager?.statusBarFrame ?? CGRect.zero)
            statusBar.backgroundColor = AppThemeColor
            statusBar.tag = 100
            UIApplication.shared.keyWindow?.addSubview(statusBar)
       
    } else {
            
            let statusBar = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView
            statusBar?.backgroundColor = AppThemeColor
         
        }
    }
}

remove status bar from the key window

func removeStatusBar(){
    
    if #available(iOS 13.0, *) {
        
        UIApplication.shared.keyWindow?.viewWithTag(100)?.removeFromSuperview()

    }
}

in viewDidLoad and viewWillAppear call above function

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    removeStatusBar()
    statusBarColorChange()
}

override func viewDidLoad() {
    super.viewDidLoad()

    removeStatusBar()
    statusBarColorChange()

}

Solution 8 - Ios

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

 }

Solution 9 - Ios

KeyWindow is deprecated in iOS13. You can use this extension for swift 5 and iOS 13 to the top

extension UIApplication {

    var statusBarUIView: UIView? {

        if #available(iOS 13.0, *) {
            let tag = 3848245

            let keyWindow: UIWindow? = UIApplication.shared.windows.filter {$0.isKeyWindow}.first

            if let statusBar = keyWindow?.viewWithTag(tag) {
                return statusBar
            } else {
                let height = keyWindow?.windowScene?.statusBarManager?.statusBarFrame ?? .zero
                let statusBarView = UIView(frame: height)
                statusBarView.tag = tag
                statusBarView.layer.zPosition = 999999

                keyWindow?.addSubview(statusBarView)
                return statusBarView
            }

        } else {

            if responds(to: Selector(("statusBar"))) {
                return value(forKey: "statusBar") as? UIView
            }
        }
        return nil
      }
}

And use it in your didFinishLaunchingWithOptions in AppDelegate class like :

UIApplication.shared.statusBarUIView?.backgroundColor = .red(any color)

Solution 10 - Ios

you can try this

if (@available(iOS 13, *))
{
    UIView *_localStatusBar = [[UIApplication sharedApplication].keyWindow.windowScene.statusBarManager performSelector:@selector(createLocalStatusBar)];
    statusBar = [_localStatusBar performSelector:@selector(statusBar)];
}
else
{
    statusBar = [[UIApplication sharedApplication] valueForKey:@"statusBar"];
}

Solution 11 - Ios

this is an ObjC version of most voted answer for those like me who are still using it:

create a category of UIApplication and add it to your project:

@implementation UIApplication (iOS13PorcoDiDio)

- (UIView*) statusBar
{
    
    if([UIDevice getOSVersion] >= 13)
    {
        
        const NSUInteger k_TAG_STATUSBAR = 38482458385;
        
        UIView * vStatusBar = [[UIApplication sharedApplication].keyWindow viewWithTag:k_TAG_STATUSBAR];
        if(vStatusBar != nil)

            return vStatusBar;
            
        else {
            
            UIView *vStatusBar = [[UIView alloc] initWithFrame:[UIApplication sharedApplication].statusBarFrame];
            [vStatusBar setTag:k_TAG_STATUSBAR];
            [[UIApplication sharedApplication].keyWindow addSubview:vStatusBar];

            return vStatusBar;
            
        }
        
    } else if([UIApplication respondsToSelector:@selector(statusBar)])
        
        return (UIView*)[UIApplication sharedApplication].statusBar;
    
    else
        
        return nil;
    
    
}

@end

Solution 12 - Ios

This is the best answer I have ever seen.. Cheers

    if #available(iOS 13.0, *) {
    let app = UIApplication.shared
    let statusBarHeight: CGFloat = app.statusBarFrame.size.height
    
    let statusbarView = UIView()
        statusbarView.backgroundColor = ColorPalette.grayChateau  
    view.addSubview(statusbarView)
  
    statusbarView.translatesAutoresizingMaskIntoConstraints = false
    statusbarView.heightAnchor
        .constraint(equalToConstant: statusBarHeight).isActive = true
    statusbarView.widthAnchor
        .constraint(equalTo: view.widthAnchor, multiplier: 1.0).isActive = true
    statusbarView.topAnchor
        .constraint(equalTo: view.topAnchor).isActive = true
    statusbarView.centerXAnchor
        .constraint(equalTo: view.centerXAnchor).isActive = true
  
} else {
    let statusBar = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView
    statusBar?.backgroundColor = UIColor.red
 }

Solution 13 - Ios

I think the simplest way is to use NavigationController instead of ViewController. Changing of Navigation Bar background using storyboard will also reflect on status bar

NavigationController

Solution 14 - Ios

Use this Extension:

extension UINavigationController {

func setStatusBar(backgroundColor: UIColor) {
    let statusBarFrame: CGRect
    if #available(iOS 13.0, *) {
        statusBarFrame = view.window?.windowScene?.statusBarManager?.statusBarFrame ?? CGRect.zero
    } else {
        statusBarFrame = UIApplication.shared.statusBarFrame
    }
    let statusBarView = UIView(frame: statusBarFrame)
    statusBarView.backgroundColor = backgroundColor
    view.addSubview(statusBarView)
}}

Solution 15 - Ios

I do this, can get statusBar,but set statusBar backgroundColor do not work

UIView *statusBar;
if (@available(iOS 13, *)) {
    UIView *_localStatusBar = [[UIApplication sharedApplication].keyWindow.windowScene.statusBarManager performSelector:@selector(createLocalStatusBar)];
    statusBar = [_localStatusBar performSelector:@selector(statusBar)];
}
else {
    statusBar = [[UIApplication sharedApplication] valueForKey:@"statusBar"];
}
if ([statusBar respondsToSelector:@selector(setBackgroundColor:)]) {
    statusBar.backgroundColor = [UIColor redColor];
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHugo AlonsoView Question on Stackoverflow
Solution 1 - IosisHiddenView Answer on Stackoverflow
Solution 2 - IosAlaa OthmanView Answer on Stackoverflow
Solution 3 - IosAjeetView Answer on Stackoverflow
Solution 4 - IosNikiView Answer on Stackoverflow
Solution 5 - IosC13View Answer on Stackoverflow
Solution 6 - IosTajinder singhView Answer on Stackoverflow
Solution 7 - IosMilan AgheraView Answer on Stackoverflow
Solution 8 - IosBASIL BABYView Answer on Stackoverflow
Solution 9 - IosSnappView Answer on Stackoverflow
Solution 10 - IosEwane ShenView Answer on Stackoverflow
Solution 11 - IosFabio NapodanoView Answer on Stackoverflow
Solution 12 - IosArchu MohanView Answer on Stackoverflow
Solution 13 - IosshalonteohView Answer on Stackoverflow
Solution 14 - IosAvneesh AgrawalView Answer on Stackoverflow
Solution 15 - IossandyView Answer on Stackoverflow