15

With iOS13 I cannot change the background color of the statusbar anymore because the statusbar is no longer accessible using "value for key". Did anybody figure out how this is possible or is there any knowledge that it will be possible in the final version of iOS13?

I came across different proposals already like using the UIApplications StatusBarView (no longer accessible in xcode 11, beta 7) or using the statusbarmanager. Both do not give access to the status bar.

let statusBar: UIView = UIApplication.shared.value(forKey: "statusBar") as! UIView
if statusBar.responds(to: #selector(setter: UIView.backgroundColor)) {
  statusBar.backgroundColor = <Some Color>
}

I expect the status bar to get the background color that I need.

HangarRash
  • 7,314
  • 5
  • 5
  • 32
Nij
  • 163
  • 1
  • 1
  • 5
  • check this answer https://stackoverflow.com/a/57152709/8687925. – SAXENA Aug 30 '19 at 12:54
  • Thanks @SAXENA - this seems to require a navigationbar to set the appearance on. I am looking for a way without navigationbar. – Nij Sep 03 '19 at 07:49
  • @Nij see this for help : [How to change the status bar background color and text color on iOS 13?](https://stackoverflow.com/questions/56651245/how-to-change-the-status-bar-background-color-and-text-color-on-ios-13) – Anbu.Karthik Sep 04 '19 at 08:41

13 Answers13

9

Objective-C Version using UIStatusBarManager:

UIView *statusBar = [[UIView alloc]initWithFrame:[UIApplication sharedApplication].keyWindow.windowScene.statusBarManager.statusBarFrame] ;
statusBar.backgroundColor = [UIColor whiteColor];
[[UIApplication sharedApplication].keyWindow addSubview:statusBar]
Lukas
  • 133
  • 5
7

Use this on your preferred ViewController

override func viewDidAppear(_ animated: Bool) {
    if #available(iOS 13, *)
    {
        let statusBar = UIView(frame: (UIApplication.shared.keyWindow?.windowScene?.statusBarManager?.statusBarFrame)!)
        statusBar.backgroundColor = UIColor.systemBackground
        UIApplication.shared.keyWindow?.addSubview(statusBar)
    }
}

you can use your Color in "UIColor.systemBackground"

Dante
  • 87
  • 4
6

Code works for Swift 5+ and iOS 13+

To change the StatusBar background colour, i have created a base class of UIViewController so that i can inherit same code in all the view controllers.

Added "statusBarColorChange()" to UIViewController extension.

extension UIViewController {

  func statusBarColorChange() {

    if #available(iOS 13.0, *) {

        let statusBar = UIView(frame: UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.windowScene?.statusBarManager?.statusBarFrame ?? CGRect.zero)
        statusBar.backgroundColor = .appNavigationThemeColor
            statusBar.tag = 100
        UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.addSubview(statusBar)

    } else {

            let statusBar = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView
            statusBar?.backgroundColor = .appNavigationThemeColor

        }
    } }

Created Base Class and inherited in other classes.

class BaseClass: UIViewController {

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

class ChatListViewController: BaseClass {} 

Hope will be helping :)

JaspreetKour
  • 777
  • 9
  • 11
2

You can just set the base view background color in your ViewController if you are not using NavigationController

view.backgroundColor = .blue
RickYip
  • 49
  • 3
1

Try this

if #available(iOS 13.0, *) {
    let navBarAppearance = UINavigationBarAppearance()
    navBarAppearance.configureWithOpaqueBackground()
    navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
    navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
    navBarAppearance.backgroundColor = <insert your color here>
    navigationBar.standardAppearance = navBarAppearance
    navigationBar.scrollEdgeAppearance = navBarAppearance
}
iShox
  • 367
  • 2
  • 10
1

The status bar will try and match the color of the app

if you have a navbar

self.navigationBar.barTintColor = UIColor.blue

or

UINavigationBar.appearance().barTintColor = UIColor.blue

if there is no navbar

view.backgroundColor = UIColor.blue

if your background is a webview

webView.scrollView.backgroundColor = UIColor.blue

there are probably more cases I'm missing

Dug
  • 315
  • 5
  • 11
0
 let appearance = UINavigationBarAppearance()
 appearance.backgroundColor = .blue
 self.navigationController?.navigationBar.scrollEdgeAppearance = appearance

I hope, this will help you.

Ajumal
  • 1,048
  • 11
  • 33
0

Call this in your base view controller

public extension UIViewController {
    func setStatusBar(color: UIColor) {
        let tag = 12321
        if let taggedView = self.view.viewWithTag(tag){
            taggedView.removeFromSuperview()
        }
        let overView = UIView()
        overView.frame = UIApplication.shared.statusBarFrame
        overView.backgroundColor = color
        overView.tag = tag
        self.view.addSubview(overView)
    }
}
midhun p
  • 1,987
  • 18
  • 24
0

JaspreetKour's answer works; but, it can be very difficult to reset the status bar color for other view controllers (especially if you need image content underneath the status bar). Setting the color to .clear does not work.

A simpler solution is to clear the navigation bar:

navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationController?.navigationBar.shadowImage = UIImage()
navigationController?.navigationBar.backgroundColor = .clear
navigationController?.navigationBar.isTranslucent = true

and then add a UIView (set the background color to the color you need) to your view controller and set its constraints to the very top of your superview (not to the margin).

With this technique, your color will show underneath the status bar and you won't need to mess with the statusBarManager (whose properties are all read only).

Mark
  • 765
  • 8
  • 12
0

Code works for Swift 5+ and iOS 13+

    public extension UIViewController {

func setStatusBar(color: UIColor) {
    
    let keyWindow = UIApplication.shared.connectedScenes
        .filter({$0.activationState == .foregroundActive})
        .compactMap({$0 as? UIWindowScene})
        .first?.windows
        .filter({$0.isKeyWindow}).first
    
    if #available(iOS 13.0, *) {
        
        let statusBar = UIView(frame: keyWindow?.windowScene?.statusBarManager?.statusBarFrame ?? CGRect.zero)
        statusBar.backgroundColor = color
        statusBar.tag = 100
        keyWindow?.addSubview(statusBar)
        
    } else {
        
        let statusBar = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView
        statusBar?.backgroundColor = color
        
    }}}

I use this answer but in this case compiler generates warning

'windows' was deprecated in iOS 15.0: Use UIWindowScene.windows on a relevant window scene instead

so this code work fine.

and in your ViewController viewDidLoad Method use this method as follows:

setStatusBar(color: UIColor(red: 28/255, green: 83/255, blue: 167/255, alpha: 1)) // or whatever color you want to set
0

There is one issue observed by following @JaspreetKour's answer, in which the status bar view is getting added again and again which makes the status bar colour darker than the applied colour, This happens if we are navigating to the same view controller multiple time by means of push/pop VC.

So I added two line of code to resolve that issue, in case any one facing same issue can check out this answer, where I removed the status bar view first before adding it again on window.

And then call it on viewDidLoad instead of viewWillAppear

func statusBarColorChange() {
    
    if #available(iOS 13.0, *) {
        if let viewStatus =  UIApplication.shared.windows.filter {$0.isKeyWindow}.first{
            viewStatus.viewWithTag(100)?.removeFromSuperview()
        }
        
        let statusBar = UIView(frame: UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.windowScene?.statusBarManager?.statusBarFrame ?? CGRect.zero)
        statusBar.backgroundColor = AppConstant.Colors.navColor
        statusBar.tag = 100
        UIApplication.shared.windows.filter {$0.isKeyWindow}.first?.addSubview(statusBar)
        
    } else {
        let statusBar = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView
        statusBar?.backgroundColor = AppConstant.Colors.navColor
    }
}

class BaseClass: UIViewController {

   override func viewDidLoad() {
       super.viewDidLoad()
       self.statusBarColorChange()
   }    
}

class ChatListViewController: BaseClass {}
Janmenjaya
  • 4,149
  • 1
  • 23
  • 43
-1

I was using central ThemeManager class where I was setting all UI colors. This is how I solved it. You can take parts of solution which fit your need:

  let sharedApplication = UIApplication.shared
  sharedApplication.delegate?.window??.tintColor = setYourColor

  if #available(iOS 13.0, *) {
        let statusBar = UIView(frame: (sharedApplication.delegate?.window??.windowScene?.statusBarManager?.statusBarFrame)!)
        statusBar.backgroundColor = setYourColor
        sharedApplication.delegate?.window??.addSubview(statusBar)
    } else {
        // Fallback on earlier versions
        sharedApplication.statusBarView?.backgroundColor = setYourColor
  }



extension UIApplication {

var statusBarView: UIView? {
    return value(forKey: "statusBar") as? UIView
   }
}
Mile Dev
  • 652
  • 6
  • 13
-2
if let statusBar = UIStatusBarManager.self as? UIView {
    if statusBar.responds(to: #selector(setter: UIView.backgroundColor)) {
        statusBar.backgroundColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
    }
}

I hope this works for you

Marco
  • 517
  • 6
  • 19