79
votes


I tried many ways to set the status bar style (default or lightcontent) but can't get it to work on a per view controller basis. I can set the status bar style for the whole app only.

Does anyone have a hint?

I tried UIViewControllerBasedStatusBarAppearance

and

-(UIStatusBarStyle)preferredStatusBarStyle{ 
    return UIStatusBarStyleLightContent; 
}

but these methods don't work.

10
And make sure that the navigation bar should not be overlapped with status bar....Rajneesh071
I used a little trick for it (and for controlling visible/hidden state) – I decided to publish it as pod 'UIViewController+ODStatusBar' (cocoapods.org/pods/UIViewController+ODStatusBar)Alex Nazarov
This is just one of dozens of APIs that Apple randomly changes the behaviour of from one version of iOS to the next and for some reason there has not been a complete developer revolt. You'll have to modify your implementation to fit the version of iOS that your app is running on and test it every time you build for a newer version.Bron Davies

10 Answers

139
votes

Have you tried this?

  1. Set "View controller-based status bar appearance" (UIViewControllerBasedStatusBarAppearance) to YES in your Info.plist. (YES is the default, so you can also just leave this value out of your plist.)

  2. In your viewDidLoad method, call [self setNeedsStatusBarAppearanceUpdate].

  3. Implement preferredStatusBarStyle, returning the status bar style that you want for this view controller.

    - (UIStatusBarStyle) preferredStatusBarStyle { 
        return UIStatusBarStyleLightContent; 
    }
    
75
votes

There is a catch here if your view controller is inside standalone UINavigationController and not a part of Storyboard based UINavigationController then above all methods fail. I came across this situation and then in order to set the status bar to light style i used following

[self.navigationController.navigationBar setBarStyle:UIBarStyleBlack];

This worked perfectly for me.

22
votes

EDIT: This solution is deprecated on iOS 9. Please choose one of the other answers.

With UIViewControllerBasedStatusBarAppearance set to NO, I was able to set the style to white text by using:

[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleBlackTranslucent;

This is because the text color on this style was white on iOS 6 and below.

UPDATE: According to @jowie you can try that on iOS8:

[UIApplication sharedApplication].statusBarStyle = UIBarStyleBlack;
14
votes

In Swift I was able to do this by writing:

let tbc : UITabBarController = self.window?.rootViewController as UITabBarController
var moreViewController : UINavigationController = tbc.moreNavigationController

moreViewController.navigationBar.barStyle = UIBarStyle.Black

Basically you're interested in the last line.
This resulted in tabbar changing to white:

enter image description here

Note that I didn't change anything in Info.plist in order to achieve this result.
For more informations regarding changing Navigation Status Bar, please check out this link: http://www.appcoda.com/customize-navigation-status-bar-ios-7/

13
votes

On viewDidLoad method, put this:

Objective C

[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
[self setNeedsStatusBarAppearanceUpdate];

Swift

UIApplication.shared.statusBarStyle = .lightContent
self.setNeedsStatusBarAppearanceUpdate()
7
votes

I bet you have your view controller embedded into a navigation controller. To avoid setting the navigation bar's style to .Black use this subclass:

class YourNavigationController: UINavigationController {
    override func childViewControllerForStatusBarStyle() -> UIViewController? {
        return topViewController
    }
}
5
votes

Swift:

let tbc : UITabBarController = self.window?.rootViewController as UITabBarController
var moreViewController : UINavigationController = tbc.moreNavigationController
moreViewController.navigationBar.barStyle = UIBarStyle.Black

Objective C:

append this to the controller.m file viewDidLoad method:

[self setNeedsStatusBarAppearanceUpdate].

then implement this method in that same controller.m file:

- (UIStatusBarStyle) preferredStatusBarStyle { 
    return UIStatusBarStyleLightContent; 
}

Official docs:

https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TransitionGuide/Bars.html

Article I wrote on my blog:

http://www.ryadel.com/2015/03/04/xcode-set-status-bar-style-and-color-in-objective-c/

1
votes

In the ViewController that you want to change the status bar's color

- (void) viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
}

- (void) viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
}
0
votes

Swift extension for this because I always forget how this works

extension UIViewController {
    // utility to set the status bar appearance
    // Note: Make sure "View controller-based status bar appearance" is set to NO in your target settings or this won't work
    func setStatusBarForDarkBackground(dark: Bool) {
        UIApplication.sharedApplication().statusBarStyle = dark ? .LightContent : .Default
        setNeedsStatusBarAppearanceUpdate()
    }
}
0
votes

Xcode 10.3,

In iPhone 8 12.4 Simulator, it is OK.

In iPhone X 12.4 Simulator, I tried all above, not OK.

Then I add it by hand, status bar consists of time, battery, cellular.

11

StatusBarView


class StatusBottomView: UIView {
    private var batteryView:BatteryView!
    private var timeLabel:UILabel!
    private var timer:Timer?

    override init(frame: CGRect) {
        super.init(frame: frame)
        addSubviews()
    }

    private func addSubviews() {
        batteryView = BatteryView()
        batteryView.tintColor = UIColor.blue
        addSubview(batteryView)
        timeLabel = UILabel()
        timeLabel.textAlignment = .center
        timeLabel.font = UIFont.systemFont(ofSize: 12)
        timeLabel.textColor = UIColor.blue
        addSubview(timeLabel)
        didChangeTime()
        addTimer()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        let h = frame.size.height
        let x: CGFloat = 80
        batteryView.frame.origin = CGPoint(x: ScreenHeight - x - DZMBatterySize.width, y: (h - DZMBatterySize.height) / 2)
        timeLabel.frame = CGRect(x: x, y: 0, width: 50, height: h)
    }

    // MARK: -- Timer

    func addTimer() {
        if timer == nil {
            timer = Timer.scheduledTimer(timeInterval: 15, target: self, selector: #selector(didChangeTime), userInfo: nil, repeats: true)
            RunLoop.current.add(timer!, forMode: .common)
        }
    }


    func removeTimer() {
        if timer != nil {
            timer!.invalidate()
            timer = nil
        }
    }


    @objc func didChangeTime() {
        timeLabel.text = TimerString("HH:mm")
        batteryView.batteryLevel = UIDevice.current.batteryLevel
    }

}

BatteryLevelView

class BatteryView: UIImageView {

    override var tintColor: UIColor! {

        didSet{ batteryLevelView.backgroundColor = tintColor }
    }

    /// BatteryLevel
    var batteryLevel:Float = 0 {

        didSet{ setNeedsLayout() }
    }

    /// BatteryLevelView
    private var batteryLevelView:UIView!

    convenience init() {

        self.init(frame: CGRect(x: 0, y: 0, width: DZMBatterySize.width, height: DZMBatterySize.height))
    }


    override init(frame: CGRect) {

        super.init(frame: CGRect(x: 0, y: 0, width: DZMBatterySize.width, height: DZMBatterySize.height))

        addSubviews()
    }

    func addSubviews() {

        batteryLevelView = UIView()
        batteryLevelView.layer.masksToBounds = true
        addSubview(batteryLevelView)

        image = UIImage(named: "battery_black")?.withRenderingMode(.alwaysTemplate)
        tintColor = UIColor.white
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        let spaceW:CGFloat = 1 * (frame.width / DZMBatterySize.width) * HJBatteryLevelViewScale
        let spaceH:CGFloat = 1 * (frame.height / DZMBatterySize.height) * HJBatteryLevelViewScale

        let batteryLevelViewY:CGFloat = 2.1*spaceH
        let batteryLevelViewX:CGFloat = 1.4*spaceW
        let batteryLevelViewH:CGFloat = frame.height - 3.4*spaceH
        let batteryLevelViewW:CGFloat = frame.width * HJBatteryLevelViewScale
        let batteryLevelViewWScale:CGFloat = batteryLevelViewW / 100

        var tempBatteryLevel = batteryLevel

        if batteryLevel < 0 {

            tempBatteryLevel = 0

        }else if batteryLevel > 1 {

            tempBatteryLevel = 1

        }

        batteryLevelView.frame = CGRect(x: batteryLevelViewX , y: batteryLevelViewY, width: CGFloat(tempBatteryLevel * 100) * batteryLevelViewWScale, height: batteryLevelViewH)
        batteryLevelView.layer.cornerRadius = batteryLevelViewH * 0.125
    }

}