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

50,527

Solution 1

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

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

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

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

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
      }
   }
Share:
50,527

Related videos on Youtube

Hugo Alonso
Author by

Hugo Alonso

Hi!, A happy human that loves being a coder over here! I'm always eager to improve my skills and explore other points of view. I started to code in C++ & Java, after several languages.., I'm now comfortably stuck with Swift. I'm really curious, so I like to get a grasp of almost every disruptive technology... I guess I'm kind of a technological polygamist 😅. Oh.. I enjoy teaching, I have been a 👨🏻‍🏫 for several years and through StackOverflow, I have had the opportunity to continue when not in the classroom. ✌🏻

Updated on July 05, 2022

Comments

  • Hugo Alonso
    Hugo Alonso almost 2 years

    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?

    • rmaddy
      rmaddy almost 5 years
      Why are you trying to manually change the status bar background color? By default it will match the color of your app.
    • Hugo Alonso
      Hugo Alonso almost 5 years
      It's a legacy app that includes a custom status bar colour making it look apart from the rest of the app
    • rmaddy
      rmaddy almost 5 years
      There has never been a valid way to modify the status bar color. Such solutions always end up breaking eventually. Never dig into the private subview structure.
    • Mike
      Mike almost 5 years
      @HugoAlonso see my answer here: stackoverflow.com/questions/56556254/…
    • Hugo Alonso
      Hugo Alonso over 4 years
      @rmaddy can you add an answer stating the fact that is not possible and what's the best approach so I can set it as the accepted one?
    • Akshay Jadhav
      Akshay Jadhav over 4 years
      youtube.com/watch?v=bZXk0Dwxopw.... refer this video
    • Akshar Darji
      Akshar Darji over 4 years
      @hugoAlonso You can check this answer: stackoverflow.com/a/57848822/2677134
  • rmaddy
    rmaddy over 4 years
    keyWindow is deprecated in iOS 13.
  • rmaddy
    rmaddy over 4 years
    keyWindow is deprecated in iOS 13.
  • rmaddy
    rmaddy over 4 years
    keyWindow is deprecated in iOS 13.
  • rmaddy
    rmaddy over 4 years
    keyWindow is deprecated in iOS 13.
  • sandy
    sandy over 4 years
    So,how to get statusBarView in OC
  • rmaddy
    rmaddy over 4 years
    There is no statusBarView to get. There is no public API for it. In iOS 13 you can get the statusBarManager from a window scene but there is no view.
  • Hugo Alonso
    Hugo Alonso over 4 years
    Why would you want to use something that's deprecated?
  • Ram G.
    Ram G. over 4 years
    can you please add methods - createLocalStatusBar and @selector(statusBar)
  • Lance Samaria
    Lance Samaria over 4 years
    @isHidden I was using the iOS version with np, updated to Xcode 11 and iOS 13 and got a crash, I checnged the extension code to your answer and no more crashes, thanks. But can you give an example on how to use your code information iOS 12 and iOS 13. Right now it just shows what to add in the extension
  • Preetam Jadakar
    Preetam Jadakar over 4 years
    as pointed by @rmaddy, keyWindow as well as statusBarFrame are both deprecated
  • rmaddy
    rmaddy over 4 years
    keyWindow is deprecated in iOS 13.
  • rmaddy
    rmaddy over 4 years
    keyWindow is deprecated in iOS 13.
  • rmaddy
    rmaddy over 4 years
    That's better, but it still isn't ideal. What happens when the app is showing two different scenes on an iPad? This code only shows the extra view above one of the scenes and not both.
  • Niki
    Niki over 4 years
    @rmaddy So should i put a for loop, and which would execute the same code for all windows ?
  • Steve Brooker
    Steve Brooker over 4 years
    Any chance of someone providing an Objective C version of this?
  • Marlhex
    Marlhex over 4 years
    'statusBarFrame' was deprecated in iOS 13.0: Use the statusBarManager property of the window scene instead.
  • Marlhex
    Marlhex over 4 years
    Value of type '[UIWindow]' has no member 'addSubview'
  • Niki
    Niki over 4 years
    @Daniella I've updated my code, would you please check your code now!
  • MMK
    MMK over 4 years
    new to iOS dev. Can anyone tell me where to use this code snippet? in AppDelegate or viewController?
  • Ajeet
    Ajeet over 4 years
    let keyWindow = UIApplication.shared.connectedScenes .filter({$0.activationState == .foregroundActive}) .map({$0 as? UIWindowScene}) .compactMap({$0}) .first?.windows .filter({$0.isKeyWindow}).first You can call directly as:- keyWindow?.addSubview(statusBar)
  • rmaddy
    rmaddy over 4 years
    Don't put code in a comment, update your answer as needed. Keep in mind that there may be two active scenes so simply grabbing the first could be wrong.
  • Roman
    Roman over 4 years
    For keyWindows: UIApplication.shared.windows.filter {$0.isKeyWindow}.first
  • Alberto Schiariti
    Alberto Schiariti over 4 years
    PorcoDiDio is deprecated in iOS 13
  • isHidden
    isHidden over 4 years
    @HugoAlonso, There are no warnings in my projects, maybe the reason is their age.
  • isHidden
    isHidden over 4 years
    @MMK in my case i use it in viewController to have ability to change the statusBar colour for different VC.
  • isHidden
    isHidden over 4 years
    @LanceSamaria to change statusBar colour write this in some place of your code. (For example in viewWillAppear or in AppDelegate): UIApplication.shared.statusBarUIView?.backgroundColor = .yellow
  • Lance Samaria
    Lance Samaria over 4 years
    @isHidden thanks for getting back to me. I figured out how to use it later that day after I asked you. I forgot what I did exactly but maybe it was what you just wrote? Any much appreciated. Happy Coding!
  • Hugo Alonso
    Hugo Alonso over 4 years
    Where is stated that the view is the one with tag 3848245?
  • isHidden
    isHidden over 4 years
    @HugoAlonso, it works for me. The tag for each subview is 0 by default. But maybe in some case the window can already has a subview with same tag. If you want to be sure that your tag is unique you can do the next: 1) create function that get UIView description and convert it to Int hash value, than use it like a tag to identify your view. 2) create function that generate random integer value and check if there are the same in window, if yes - generate new random value, no - use it like a tag. 3) try to find some docs where is stated that your tag is unique.
  • Patrick
    Patrick over 4 years
    Best answer of all
  • Niki
    Niki over 4 years
    @jayantrawat yes, In didFinishLaunchingWithOptions application method within APPDELEGATE.
  • jayant rawat
    jayant rawat over 4 years
    @Niki its not working for me with Xcode 11/iOS13 & UIApplication.shared.statusBarView is also not available in Xcode11...
  • Vinayak Bhor
    Vinayak Bhor about 4 years
    Perfect Solution!
  • Giuseppe Garassino
    Giuseppe Garassino over 3 years
    'statusBarFrame' was deprecated in iOS 13.0: Use the statusBarManager property of the window scene instead. 'keyWindow' was deprecated in iOS 13.0: Should not be used for applications that support multiple scenes as it returns a key window across all connected scenes...
  • D. B.
    D. B. over 3 years
    How about the check if the statusBar view was added already? This is to make sure we do not add same subview again and again.
  • Artiom
    Artiom over 3 years
    the problem with this solution is that statusBarFrame is nil in case you call it in viewDidLoad or viewWillAppear. Works only in viewDidAppear what does not sound as a best place to set up UI
  • Ben
    Ben over 3 years
    If you are unsure how to call this like I was, in viewDidAppear (thanks @Artiom) call self.navigationController?.setStatusBar(backgroundColor: yourColor) AND self.navigationController?.navigationBar.setNeedsLayout()
  • Ben
    Ben over 3 years
    Alternatively, you can call self.navigationController?.setStatusBar(backgroundColor: yourColor) in viewWillAppear
  • karthikeyan
    karthikeyan over 3 years
    How about notch device?
  • Snapp
    Snapp over 3 years
    It works on all kind of device even notch device.
  • Admin
    Admin about 3 years
    @isHidden, how can I apply it to swiftUI
  • Andy Weinstein
    Andy Weinstein almost 3 years
    This works for me but... (I am making black status bar with white text, working without a NavController). I found that in my first viewController I had to put the code from this answer in viewDidAppear for it to work. In subsequent viewControllers in the flow I put it in viewWillAppear. I am also using this solution - which works for a non-NavController scenario: stackoverflow.com/a/17768797/826946. That makes the statusbar text white. Also not using the pre-OS13 part
  • justdan0227
    justdan0227 over 2 years
    I'm getting a warning of : 'keyWindow' was deprecated in iOS 13.0: Should not be used for applications that support multiple scenes as it returns a key window across all connected scenes
  • Nilay Dagdemir
    Nilay Dagdemir over 2 years
    "Value of type 'UIApplication' has no member 'statusBarView'" error occured for Swift 5.
  • David.C
    David.C over 2 years
    this is not working.
  • Eduard Streltsov
    Eduard Streltsov over 2 years
    @Skysoft13 it's completely different story for SwiftUI. Here's a solution I use stackoverflow.com/questions/62207272/…
  • Eduard Streltsov
    Eduard Streltsov over 2 years
    It would be great to see which settings in the attribute inspector were changed, cause when I changed the title background in NavigationController it didn't affect the status bar background
  • Sentry.co
    Sentry.co over 2 years
    'windows' was deprecated in iOS 15.0: Use UIWindowScene.windows on a relevant window scene instead