iOS 7 and later: set status bar style per view controller

IosCocoa Touch

Ios Problem Overview



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.

Ios Solutions


Solution 1 - Ios

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

Solution 2 - Ios

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.

Solution 3 - Ios

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;

Solution 4 - Ios

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/

Solution 5 - Ios

On viewDidLoad method, put this:

Objective C

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

Swift

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

Solution 6 - Ios

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

Solution 7 - Ios

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/

Solution 8 - Ios

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];
}

Solution 9 - Ios

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

Solution 10 - Ios

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


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
QuestionVan Du TranView Question on Stackoverflow
Solution 1 - IosGregView Answer on Stackoverflow
Solution 2 - Iosvishal dharankarView Answer on Stackoverflow
Solution 3 - IoscaulitomazView Answer on Stackoverflow
Solution 4 - IosFengsonView Answer on Stackoverflow
Solution 5 - IosJota Freitas JrView Answer on Stackoverflow
Solution 6 - IosSoftDesignerView Answer on Stackoverflow
Solution 7 - IosDarksealView Answer on Stackoverflow
Solution 8 - IosjxdwinterView Answer on Stackoverflow
Solution 9 - Iosn13View Answer on Stackoverflow
Solution 10 - IosdengAproView Answer on Stackoverflow