64

In XCode 7.3.x ill changed the background Color for my StatusBar with:

func setStatusBarBackgroundColor(color: UIColor) {
guard  let statusBar = UIApplication.sharedApplication().valueForKey("statusBarWindow")?.valueForKey("statusBar") as? UIView else {
    return
}
statusBar.backgroundColor = color
}

But it seems that this is not working anymore with Swift 3.0.

Ill tried with:

func setStatusBarBackgroundColor(color: UIColor) {
guard  let statusBar = (UIApplication.shared.value(forKey: "statusBarWindow") as AnyObject).value(forKey: "statusBar") as? UIView else {
    return
}
statusBar.backgroundColor = color
}

But it gives me:

this class is not key value coding-compliant for the key statusBar.

Any Ideas how to change it with XCode8/Swift 3.0?

Krunal
  • 77,632
  • 48
  • 245
  • 261
derdida
  • 14,784
  • 16
  • 90
  • 139

16 Answers16

158
extension UIApplication {
    var statusBarView: UIView? {
        if responds(to: Selector(("statusBar"))) {
            return value(forKey: "statusBar") as? UIView
        }
        return nil
    }
}

UIApplication.shared.statusBarView?.backgroundColor = .red

Update for iOS 13

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.

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

Callam
  • 11,409
  • 2
  • 34
  • 32
  • 24
    This isn't a good practice at all, I highly discourage to use this method since this `UIView` is private. I am curious to see if your app gets approved using this. – iGranDav Dec 13 '16 at 23:06
  • @iGranDav Why isn't this good practice. The method ```value(forKey key: String)``` is open so I'm assuming its ok to use. Can you please explain. If this is bad practice, how would you change the background color or the status bar. This methd has worked for me. I've tried adding a subview to the ```window``` object in the ```AppDelegate``` and that didn't work. – breaktop Dec 21 '16 at 23:30
  • 4
    @breaktop using the `value(forKey key: String)` method you are using the KVC of objc runtime to access a view you shouldn't have access to (and has no documentation referring to it BTW) during runtime only. This construction is used under iOS 10 but not under iOS 9 for instance (where you need to access the `statusBarWindow` first), and you have *absolutely* no clue that it will persists under iOS 11. Internal construction and no docs means that Apple does not have any contract to respect here. – iGranDav Dec 26 '16 at 10:23
  • Did anyone face app rejection by using this code? or it is safe to use? – Sanket_B Mar 29 '18 at 10:20
  • 6
    @SanketBhavsar I have not faced a rejection for using it as of yet – Callam Mar 29 '18 at 11:08
  • 2
    I have problem with this method on iPhone X. The background color becomes transparent when app switcher (home indicator) gesture is activated. – fahrulazmi Apr 16 '18 at 15:31
  • keyWindow is deprecated in iOS 13. – hong developer Nov 27 '19 at 10:09
  • UIApplication.shared.statusBarUIView?.backgroundColor = .white – Jainil Patel Feb 10 '20 at 12:04
  • Doesn't work on xcode12. App crashes with, Thread 1: "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." – Faizyy Feb 13 '21 at 14:54
64

"Change" status bar background color:

let statusBarView = UIView(frame: UIApplication.shared.statusBarFrame)
let statusBarColor = UIColor(red: 32/255, green: 149/255, blue: 215/255, alpha: 1.0)
statusBarView.backgroundColor = statusBarColor
view.addSubview(statusBarView)

Change status bar text color:

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
}

Update: please note that the status bar frame will change when the view is rotated. You could update the created subview frame by:

  • Using the autoresizing mask: statusBarView.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
  • Observing NSNotification.Name.UIApplicationWillChangeStatusBarOrientation
  • Or overriding viewWillLayoutSubviews()
Daniel Illescas
  • 5,346
  • 3
  • 17
  • 23
31

With using Swift 3 and 4 you can use the code snippet on below. It finds the view from UIApplication using valueForKeyPath as set it's background color.

guard let statusBarView = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView else {
        return
    }
statusBarView.backgroundColor = UIColor.red

Objective-C

UIView *statusBarView = [UIApplication.sharedApplication valueForKeyPath:@"statusBarWindow.statusBar"];
if (statusBarView != nil)
{
    statusBarView.backgroundColor = [UIColor redColor];
}
abdullahselek
  • 7,893
  • 3
  • 50
  • 40
9

For Xcode 9 and iOS 11: The style of the status bar we will try to achieve is a status bar with white content. Go to the ViewController.swift file and add the following lines of code.

override var preferredStatusBarStyle: UIStatusBarStyle {

     return .lightContent

}

Or from project settings option you can change status bar's style:

enter image description here

Next, go back to the Storyboard, Select the View Controller and in the Editor menu Select Embed in Navigation Controller. Select the Navigation Bar and in the Attribute Inspector set the Bar Tint color to red. The Storyboard will look like this. enter image description here

Build and Run the project, The content of the status bar is dark again, which is the default. The reason for this is, iOS asked for the style of the status bar of the navigation controller instead of the contained view controller.

enter image description here

To change the style of all navigation controller inside the app, change the following method in the AppDelegate.swift file.

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

    UINavigationBar.appearance().barStyle = .blackOpaque
    return true
    }

Build and Run the Project again, this time the content of the status bar changed to white.

enter image description here

Jamil Hasnine Tamim
  • 4,389
  • 27
  • 43
6

I have a custom solution for changing status bar on iOS 13 and below. Here is how to do that:

if #available(iOS 13.0, *) {
   let app = UIApplication.shared
   let statusBarHeight: CGFloat = app.statusBarFrame.size.height

   let statusbarView = UIView()
   statusbarView.backgroundColor = UIColor.red
   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
}

Gist

Also, check the article iOS 13 How to Change StatusBar Color?

One last thing, you can still change statusbar style with :

 override var preferredStatusBarStyle : UIStatusBarStyle {
    return UIStatusBarStyle.lightContent
    //return UIStatusBarStyle.default   // Make dark again
}
FreakyCoder
  • 840
  • 11
  • 24
5

For iOS 11 and Xcode 9 use the following steps.

  1. create an extention to UIApplication class:

    extension UIApplication { var statusBarView: UIView? { return value(forKey: "statusBar") as? UIView } }

  2. In your class or wherever you want to change the Status bar's background color:

    UIApplication.shared.statusBarView?.backgroundColor = .red

  3. For light content or dark content of status bar simply go to Info.plist and add the following value row with value NO.

View controller-based status bar appearance

  1. Now just set the light content or whatever you need in the General Tab of your project's settings.
Asfand Shabbir
  • 1,234
  • 13
  • 9
4
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any] ?) -> Bool {
    // Override point for customization after application launch.

    UINavigationBar.appearance().barStyle = .blackOpaque
    return true
}

This works for me, as my navigation barTintColor was black and unable to see the status bar.

When set above code it didFinishLaunch status bar appears in white.

anothernode
  • 5,100
  • 13
  • 43
  • 62
ioSana
  • 117
  • 2
4

write this in first view controller:

UIApplication.shared.statusBarUIView?.backgroundColor = .white






extension UIApplication {
    var statusBarUIView: UIView? {
        if #available(iOS 13.0, *) {
            let tag = 38482458385
            if let statusBar = self.keyWindow?.viewWithTag(tag) {
                return statusBar
            } else {
                let statusBarView = UIView(frame: UIApplication.shared.statusBarFrame)
                statusBarView.tag = tag

                self.keyWindow?.addSubview(statusBarView)
                return statusBarView
            }
        } else {
            if responds(to: Selector(("statusBar"))) {
                return value(forKey: "statusBar") as? UIView
            }
        }
        return nil
    }
}
Jainil Patel
  • 1,284
  • 7
  • 16
  • '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 – Sentry.co Dec 11 '21 at 16:19
  • When i wrote the answer i was learning shift language. So it is too old answer. – Jainil Patel Dec 15 '21 at 16:53
  • no worries. Just letting future internet dwellers know that iOS has changed how this works. Currently I'm using this solution: https://gist.github.com/eonist/ffc0788c57d620aac43ae15cec4b00a9 – Sentry.co Dec 16 '21 at 03:50
3

I made this extension to change color of status bar. It's not dependent on the key. So it is much safer to use

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)
    }
}

Here is usage anywhere in viewcontroller:

setStatusBar(color: .red)

Rifat Monzur
  • 640
  • 1
  • 5
  • 11
2

Try this

Goto your app info.plist

  1. Set View controller-based status bar appearance to NO
  2. Set Status bar style to UIStatusBarStyleLightContent

Then Goto your app delegate and paste the following code where you set your Windows's RootViewController.

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0"))
{
    UIView *view=[[UIView alloc] initWithFrame:CGRectMake(0, 0,[UIScreen mainScreen].bounds.size.width, 20)];
    view.backgroundColor=[UIColor blackColor];
    [self.window.rootViewController.view addSubview:view];
}
vipinsaini0
  • 541
  • 1
  • 7
  • 26
1

Previous Code:-

func setStatusBarBackgroundColor(color: UIColor) {
        guard let statusBar = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView else { return }

        statusBar.backgroundColor = color
    }

My application got a crash show 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.'

Updated Code-

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

This code is working swift 5.2

enter image description here

Kumar
  • 59
  • 1
  • 6
0

You can set background color for status bar during application launch or during viewDidLoad of your view controller.

extension UIApplication {

    var statusBarView: UIView? {
        return value(forKey: "statusBar") as? UIView
    }

}

// Set upon application launch, if you've application based status bar
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        UIApplication.shared.statusBarView?.backgroundColor = UIColor.red
        return true
    }
}


or 
// Set it from your view controller if you've view controller based statusbar
class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        UIApplication.shared.statusBarView?.backgroundColor = UIColor.red
    }

}



Here is result:

enter image description here

Krunal
  • 77,632
  • 48
  • 245
  • 261
  • 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.' – Sentry.co Dec 11 '21 at 16:15
  • @Sentry.co - I tested and posted this answer 3 years back. You are welcomed to update this answer and improve its quality to make it aligned with latest technological changes in Swift/iOS. – Krunal Dec 13 '21 at 02:51
  • Yepp. My comment is intended to warn people that are trying to solve this too look else where as it wont work anymore. I got it working now but it requires a lot of research as no-one has it worked out on StackOverflow yet. Here is the solution that is working for iOS 15. (its not elegant at all) https://gist.github.com/eonist/ffc0788c57d620aac43ae15cec4b00a9 – Sentry.co Dec 13 '21 at 15:53
0

The possible solution is adding view that will be used as background of statusBar on your viewController:

let frame = screenController.view.convert(UIApplication.shared.statusBarFrame, to: screenController.view)
let backview = UIView(frame: frame)

backview.backgroundColor = backgroundColor
screenController.view.addSubview(backview)
screenController.view.bringSubviewToFront(backview)
Daniil Chuiko
  • 866
  • 8
  • 7
0

Add following code in your extension file to edit your status bar in swift 4 and Above:

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

now, we can edit status bar by adding following line in our ViewController class:

UIApplication.shared.statusBarView?.backgroundColor = <Your Color name>

ex: UIApplication.shared.statusBarView?.backgroundColor = .red

Hope, this will be helpful. Thanks

0

IOS 15, Xcode 13.2.1, Swift 5

I was able to get this to work without errors or warnings using the following:

func statusBarColor() {
    if #available(iOS 13.0, *) {
        
        let statusBar2 =  UIView()
        if UIApplication.shared.currentScene?.statusBarManager!.statusBarFrame != nil {
            statusBar2.frame = (UIApplication.shared.currentScene?.statusBarManager!.statusBarFrame)!
            statusBar2.backgroundColor = UIColor.init(named: "BackGroundColor")
            UIApplication.shared.windows.first?.addSubview(statusBar2)
        }
    } else {
        let statusBar2: UIView = UIApplication.shared.value(forKey: "statusBar") as! UIView
        statusBar2.backgroundColor = UIColor.init(named: "BackGroundColor")
    }
}

Use: Call the function in viewDidLoad for single scene applications or applications with only a single statusBar color change needed. For applications with multiple scenes calling for different statusBar colors I recommend calling the function in viewWillAppear.

Michael
  • 1
  • 3
0

All the solution are outdated. After doing research for about 3 hours, Here is the best solution for all iOS versions in Swift 5.5

I am making an extension of UIViewController which will be easy to use on any viewController.

// MARK: Change status bar color
extension UIViewController {
    public func setStatusBarBackgroundColor(_ color: UIColor) {
        if #available(iOS 13.0, *) {
            // get the window scene and status bar manager for iOS>13.0
            guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
                  let statusBarManager = windowScene.statusBarManager
            else {
                return
            }
            // get the status bar height
            let statusBarHeight: CGFloat = statusBarManager.statusBarFrame.size.height

            let statusbarView = UIView()
            // change your color
            statusbarView.backgroundColor = color
            view.addSubview(statusbarView)
            statusbarView.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                statusbarView.topAnchor.constraint(equalTo: view.topAnchor),
                statusbarView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                statusbarView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
                statusbarView.heightAnchor.constraint(equalToConstant: statusBarHeight)
            ])
        } else {
            let statusBar = UIApplication.shared.value(forKeyPath: "statusBarWindow.statusBar") as? UIView
            statusBar?.backgroundColor = color
        }
    }
}

If you have any confusion please let me know. Also if you want to change status bar color according to view controller then follow this step

first changethe "View controller-based status bar appearance" key in the Info.plist, make sure it is set to "YES" like below picture enter image description here

and add this code.

  override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }

Note The preferredStatusBarStyle property won't get called if the view controller is embedded in another container view controller, e.g., UINavigationController.

so, you have to assign like this

class YourNavigationController: UINavigationController {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
}

And If you want a navigation controller to give control of the status bar style to its children, override the childForStatusBarStyle property and return any child view controllers that you want to determine the status bar style.

override var childForStatusBarStyle: UIViewController? {
    return visibleViewController
}

Chuck this code in your YourNavigationController class.

Best up luck!!!

Amrit Tiwari
  • 922
  • 7
  • 21