iOS 7及以上版本:为每个视图控制器设置状态栏样式

79


我尝试了多种方法来设置状态栏的样式(默认或浅色内容),但无法在每个视图控制器上单独实现。我只能为整个应用程序设置状态栏样式。

有人有提示吗?

我尝试过UIViewControllerBasedStatusBarAppearance

-(UIStatusBarStyle)preferredStatusBarStyle{ 
    return UIStatusBarStyleLightContent; 
}

但是这些方法不起作用。


https://dev59.com/SGMk5IYBdhLWcg3wxAvy#18980833 - Rajneesh071
1
请确保导航栏不会与状态栏重叠... - Rajneesh071
我使用了一个小技巧(以及控制可见/隐藏状态),我决定将其发布为pod 'UIViewController+ODStatusBar'(https://cocoapods.org/pods/UIViewController+ODStatusBar) - Alex Nazarov
1
这只是苹果随机更改行为的数十个API之一,从一个iOS版本到另一个版本。出于某种原因,开发者并没有完全反抗。您将不得不修改您的实现以适应您的应用程序正在运行的iOS版本,并在构建新版本时每次进行测试。 - Bron Davies
10个回答

139

你试过这个吗?

  1. 在你的 Info.plist 中将“View controller-based status bar appearance”(UIViewControllerBasedStatusBarAppearance)设置为YES。(YES是默认值,所以你也可以不用在plist中指定。)

  2. 在你的viewDidLoad方法中,调用[self setNeedsStatusBarAppearanceUpdate]

  3. 实现preferredStatusBarStyle,返回你想要此视图控制器的状态栏样式。

- (UIStatusBarStyle) preferredStatusBarStyle { 
    return UIStatusBarStyleLightContent; 
}

抱歉,我搞反了。UIViewControllerBasedStatusBarAppearance 应该是 YES(这也是默认值,所以你不需要使用它)。我在我的回答的第一步中进行了更正。 - Greg
2
这在iPhone 5 + iOS7上不起作用。UIViewControllerBasedStatusBarAppearance为NO,而[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackTranslucent];对我的情况很有效 :) - Femina
4
如果你将那段代码放在自定义的UINavigationController子类中,它就可以与基于UINavigationController的应用程序一起使用。 - anneblue
3
不需要第二步。 - pronebird
4
在iOS 8上对我无效。这只是更改默认设置。我需要的是白色,现在变成了默认设置。 - noobsmcgoobs
显示剩余5条评论

76

这里有一个小技巧,如果您的视图控制器在独立的UINavigationController内而不是基于Storyboard的UINavigationController的一部分,则所有上述方法都将失败。我遇到了这种情况,为了将状态栏设置为浅色风格,我使用了以下方法

[self.navigationController.navigationBar setBarStyle:UIBarStyleBlack];

这对我来说完美地起作用了。


8
如果您的导航控制器的导航栏被隐藏,这个功能就无法使用。 - Matthew Quiros
类似的建议也适用于 UISplitViewController。我最终选择了子类化。 - Stephen Darlington
1
据我理解,UINavigationBar.barStyle 会覆盖 preferredStatusBarStyle。无论你如何设置 preferredStatusBarStyle,一个该死的 UINavigationBar.setBarStyle 就会接管一切。 - Desmond DAI

22

编辑:此解决方案在iOS 9上已过时。请从其他答案中选择一个。

UIViewControllerBasedStatusBarAppearance设置为NO时,我可以使用以下方式将样式设置为白色文本:

[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleBlackTranslucent;

这是因为在iOS 6及以下版本中,此样式的文本颜色是白色。

更新:根据@jowie的说法,您可以在iOS8上尝试此操作:

[UIApplication sharedApplication].statusBarStyle = UIBarStyleBlack;

你仔细读了问题吗?他正在寻找iOS7的解决方案,而且是浅色风格,而不是你所提供的深色风格。 - vishal dharankar
它适用于iOS7。我仔细阅读了它。关于UIBarStyleBlackTranslucent,它之所以有效是因为在iOS6上,这种样式是黑色背景(半透明)和白色文本。当你在iOS7上这样做时,它只显示白色文本。我知道它看起来很不专业,但这是我找到的唯一真正控制栏的方法。 - caulitomaz
对于iOS 8,请使用UIBarStyleBlack - jowie
谢谢 @MatthieuRiegler,我会放置一则通知。 - caulitomaz

14
在Swift中,我能够通过编写以下代码来实现这一点:
let tbc : UITabBarController = self.window?.rootViewController as UITabBarController
var moreViewController : UINavigationController = tbc.moreNavigationController

moreViewController.navigationBar.barStyle = UIBarStyle.Black

基本上,您对最后一行感兴趣。
这导致标签栏变为白色:

enter image description here

请注意,我没有改变Info.plist中的任何内容就实现了这个结果。
有关更改导航状态栏的更多信息,请查看此链接: http://www.appcoda.com/customize-navigation-status-bar-ios-7/


这个可以工作。但是它没有使用新的"UIStatusBarStyleLightContent",我在想这是否是一种未来的解决方案?但它仍然解决了问题! - Van Du Tran
1
本来是个很好的答案,但如果你的导航栏被隐藏了就不起作用了。 - Matthew Quiros

13
在viewDidLoad方法中,加入以下代码:

Objective C

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

快捷

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

我很高兴能帮助你,Gagan。 - Jota Freitas Jr
似乎很奇怪,视图控制器正在更新整个应用程序的属性 - 解决方案应该是针对整个应用程序(位于“AppDelegate”中)或每个视图控制器。 - Zorayr
这个方法的 Swift 等效代码是:UIApplication.shared.setStatusBarStyle(UIStatusBarStyle.LightContent, animated: false)。 - minhazur
为了使其正常工作,必须在目标属性中将“基于视图控制器的状态栏外观”设置为NO。我认为这是最好的方法,因为它简单明了。 - n13

7

我打赌你将你的视图控制器嵌入了一个导航控制器。为了避免设置导航栏样式为.Black,请使用这个子类:

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

5

Swift:

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

Objective C:

将以下代码添加到controller.m文件的viewDidLoad方法中:

[self setNeedsStatusBarAppearanceUpdate].

然后在同一个controller.m文件中实现这个方法:

- (UIStatusBarStyle) preferredStatusBarStyle { 
    return UIStatusBarStyleLightContent; 
}

官方文档:

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

我在博客上写的文章:

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

这里有两个链接,一个是苹果官方的文档,另一个是关于如何在Objective-C中设置状态栏风格和颜色的博客文章。您可以访问这些链接以获取更多信息。

1
在您想要更改状态栏颜色的ViewController中
- (void) viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDefault];
}

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

0

写这个 Swift 扩展是因为我总是忘记这个怎么用

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

Xcode 10.3,

在 iPhone 8 12.4 模拟器中,一切正常。

在 iPhone X 12.4 模拟器中,我尝试了所有方法,但都不行。

然后我手动添加了状态栏,包括时间、电池和蜂窝网络。

11

状态栏视图


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
    }

}

电池电量视图

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
    }

}



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接