如何在Swift 3中设置状态栏样式

203

我正在使用Xcode 8.0 beta 4。

在之前的版本中,UIViewController有方法可以设置状态栏样式。

public func preferredStatusBarStyle() -> UIStatusBarStyle

然而,我发现在Swift 3中它变成了一个 "仅获取变量"。

public var preferredStatusBarStyle: UIStatusBarStyle { get } 

我该如何为我的UIViewController提供样式?


请尝试以下代码:var preferredStatusBarStyle: UIStatusBarStyle = .lightContent - Anbu.Karthik
33个回答

516

[更新] 适用于Xcode 10+和Swift 4.2+

这是iOS 7及更高版本的首选方法

在应用程序的Info.plist中将View controller-based status bar appearance设置为YES

在每个视图控制器中覆盖preferredStatusBarStyle(Apple文档)。例如:

override var preferredStatusBarStyle: UIStatusBarStyle {     
      return .lightContent
}
如果您的preferredStatusBarStyle基于视图控制器内部的某些更改(例如滚动位置或显示的图片是否为深色),返回不同的首选状态栏样式,那么当该状态发生变化时,您将需要调用setNeedsStatusBarAppearanceUpdate()iOS7之前的版本,已弃用的方法。 Apple已将其弃用,因此它将在未来被删除。请使用上述方法,以便在下一个iOS版本发布时无需重写代码。
如果您的应用程序支持,在应用程序的Info.plist中,将View controller-based status bar appearance设置为NO
appDelegate.swift中的didFinishLaunchingWithOptions函数中添加:
UIApplication.shared.statusBarStyle = .lightContent

导航控制器

如果您使用导航控制器,并且希望每个视图控制器的首选状态栏样式被使用并在应用程序的info.plist中设置View controller-based status bar appearanceYES

extension UINavigationController {
   open override var preferredStatusBarStyle: UIStatusBarStyle {
      return topViewController?.preferredStatusBarStyle ?? .default
   }
}

4
可以,对我来说没问题。我忘记先将新设置插入 Info.plist 中了。 - falsecrypt
1
@LightMan,uiapplication statusBarStyle并没有被弃用,我在iOS 11中使用它仍然有效。 - Sushobhit
1
@Sushobhit,setStatusBarStyle在iOS 9中已被弃用,正如此答案中所使用的一样。但是,您仍然可以使用UIApplication.statusBarStyle作为只读属性。 - LightMan
1
请注意,这对于嵌入导航控制器的视图控制器无效:请改变导航控制器的工具栏样式。 - Pranav Kasetti
9
您还可以在appDelegate.swift中删除该行,并转到Target->General->Deployment Info->状态栏样式->浅色。 - Robert Veringa
显示剩余5条评论

178

最新更新(Xcode 10+ / Swift 4.2+)

本文旨在供有意识了解过去几年中不同方法背后逻辑的人使用,内容未做任何修改。同时,从 Xcode 10,Swift 4.2 开始,第一种方法已弃用,不再受支持(即使您尝试使用它,也不会生效)。为了更好地理解 Plist.info 标志和自定义实践背后的原因,仍可参考此方法。

重要澄清

非常重要的是要了解两种自定义状态栏外观的方法。它们是不同的,不应混淆使用。

第一种方法 - 整个应用颜色相同(自iOS7以来已弃用)

在 info.plist 中找到或创建一个名为

View controller-based status bar appearance

并将其设置为NO

它是做什么用的?它本质上建立了一个设置,表明在您的应用程序中,状态栏外观不是由每个视图控制器单独定义的。这非常重要。这意味着您拥有整个应用程序的统一设置,适用于所有屏幕。有两个设置:default 是黑色文本白底,lightContent 是白色文本黑底。

要设置这其中之一(所有屏幕使用同一设置):

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    application.statusBarStyle = .lightContent // .default
    return true
}

这样,您就不需要在每个视图控制器上重新建立此设置。但是,您始终可以采用此方法自愿更改外观。

第二种方法 - 为每个视图控制器设置单独的颜色

这与第一种方法相反。要使其起作用,请前往info.plist并设置

View controller-based status bar appearance

YES

这样,每当打开新的视图控制器时,如果您在每个UIViewController实例中插入此实现,则可以单独设置状态栏样式:

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent // .default
}

你可以像第一次设置一样,在状态栏上设置暗色或浅色样式,每个视图控制器都可以单独设置。

UIKit 在两种情况下获取此属性:

  1. 在屏幕初始化时,准备 UI 时。
  2. 在代码中调用 setNeedsStatusBarAppearanceUpdate() 时。

在后一种情况下,您可以通过以下代码来操纵状态栏外观:

var isDark = false {
    didSet {
        setNeedsStatusBarAppearanceUpdate()
    }
}

override var preferredStatusBarStyle: UIStatusBarStyle {
    return isDark ? .lightContent : .default
}

func toggleAppearance() {
   isDark.toggle()
}

那么,每当您调用toggleAppearance()时,状态栏样式将被触发更改。

第三种方法-黑科技!

有一个黑科技可以直接访问状态栏:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    
    if let statusBar = UIApplication.shared.value(forKey: "statusBar") as? UIView {
        statusBar.backgroundColor = UIColor.blue
    }
    
    return true
}

为什么要进行黑客攻击?如果您需要除了黑色或白色以外的状态栏颜色,可以使用未记录的API。通过KVC获取statusBar对象并设置其背景颜色。您以这种方式获取的对象是UIStatusBar,它是从UIView派生的,因此自然支持backgroundColor属性。这是不合法的方法,但迄今为止它是设置自定义状态栏颜色的唯一方法(不考虑UINavigationBar方法,该方法允许同时自定义导航栏和状态栏外观)。这可能会导致您的应用程序被拒绝。但也许你很幸运。如果在某些复杂情况下(例如嵌套的子导航和视图控制器层次结构)这可能是唯一的方法,或者至少是更不麻烦的方法来自定义状态栏外观(例如,使其透明)。

Xcode 10+,Swift 4.2

没有其他选择了:开发人员应该让每个视图控制器定义状态栏外观,通过将标志设置为YES(或省略此操作,因为默认情况下为YES),并遵循上述说明。


额外内容

基于黑客攻击的解决方案,您可能会(虽然不鼓励)在复杂情况下使用,以便在任何阶段自愿更改状态栏外观。就颜色而言,以下扩展方法正是您可以用常规方法完成的操作。您可以根据需要进行调整。

extension UIViewController {
    func setStatusBarStyle(_ style: UIStatusBarStyle) {
        if let statusBar = UIApplication.shared.value(forKey: "statusBar") as? UIView {
            statusBar.backgroundColor = style == .lightContent ? UIColor.black : .white
            statusBar.setValue(style == .lightContent ? UIColor.white : .black, forKey: "foregroundColor")
        }
    }
}

2
一旦您拥有状态栏,您还可以执行以下操作: statusBar.setValue(UIColor.red, forKey: "foregroundColor"); 或使用任何现有的键来设置任何可用于UIStatusBar但不适用于UIView的属性。 - Mark
应用程序.statusBarStyle = .lightContent 这种方法通常自iOS9以来已经过时了。'statusBarStyle'的Setter在iOS 9.0中已被弃用:请使用-[UIViewController preferredStatusBarStyle]。前进的方式是针对UIViewController。 - toxicsun
这是更改应用程序颜色主题时唯一有效的方法。然而,似乎一旦设置了它,切换视图控制器时总是需要重新设置。从此处开始,preferredStatusBarStyle() 方法将被忽略(即使在 info.plist 中正确设置)。 - nontomatic
2
这个答案相比其他答案更加详细。 - ViruMax
3
奖励解决方案在iOS 13.1中出现故障。 - ViruMax
能否为启动屏幕设置状态栏样式?您无法为启动屏幕视图控制器设置自定义类。 - Indiana Kernick

132

你可以尝试覆盖返回的值,而不是设置它。该方法被声明为{ get },所以只需提供一个getter:

 override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
}
如果您按条件设置它,那么在准备好时,您需要调用setNeedsStatusBarAppearanceUpdate()以便它在动画更改。

2
这是更好的方法,因为您可以选择在某些视图中使用 prefersStatusBarHidden。如果您选择 UIApplication.shared.statusBarStyle,那么您将被困在其中。 - superarts.org

110

Swift 3和4,iOS 10和11,Xcode 9和10
对我来说,这种方法不起作用:

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
}

我曾经使用每个视图控制器,但这个方法行不通:

  • 在 info.list 文件中添加一行:View controller-based status bar appearance 并将其设置为 NO

  • 接下来��� appdelegate 中:

  • UIApplication.shared.statusBarStyle = .lightContent
    

我之前只尝试在应用程序委托中添加代码,但是 info plist 的设置对我很有帮助。谢谢。 - Akhilesh Sharma
6
iOS 9.0已经弃用'statusBarStyle'的Setter方法,请使用'-[UIViewController preferredStatusBarStyle]'。 - Reimond Hill

53

Xcode 10或更高版本

在Swift 5中测试通过

无需编写代码,只需按照以下步骤进行操作。

如果您想要在整个应用程序中更改状态栏。

  1. 从项目导航器(左侧面板)中选择项目。
  2. 选择目标。
  3. 选择常规选项卡。
  4. 找到部署信息。
  5. 将状态栏样式更改为浅色(对于深色背景使用"浅色",对于浅色背景使用"默认"

不要忘记info.plist的更改

  1. 选择信息选项卡
  2. 将此键添加到您的plist文件中:“View controller-based status bar appearance”= NO

运行项目并检查它。

我的项目在Swift 5和Xcode 10.2 & 11.0中。


对于Xcode 10/Swift5,这应该是被接受的答案。你必须同时执行这两个步骤才能使其正常工作。 - John Robi
这是完美的答案。 - nikhilgohil11
这对于使用Swift 5的Xcode 11也完全适用,谢谢。 - Luis Santiago
这仍然运行良好!如果您的应用程序始终为暗色或始终为亮色,这非常棒。如果您直接编辑Info.plist文件而不是通过XCode UI进行编辑,则需要设置的键是:UIStatusBarStyle UIStatusBarStyleLightContent UIViewControllerBasedStatusBarAppearance - undefined

40
如果您想更改UINavigationController中包含的所有视图的状态栏颜色为白色,请在AppDelegate中添加以下内容:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.

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

这段代码:

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
}

不适用于包含在UINavigationController中的UIViewControllers,因为编译器会查找UINavigationControllerstatusBarStyle,而不是其中包含的ViewControllersstatusBarStyle。希望这能帮助那些没有成功使用已接受答案的人!


是的,非常感谢你!导航控制器是一些人没有考虑到的小细节。 - Alexis Candelaria
刚刚花了将近三个小时的时间来寻找解决方案,这是我找到的唯一一个。非常感谢! - sparkhead95

27
如果您想在视图出现后的任何时候更改状态栏样式,可以使用以下方法:
  • 在info.list文件中添加一行:View controller-based status bar appearance并将其设置为YES

    var viewIsDark = Bool()
    
    func makeViewDark() {
    
        viewIsDark = true
        setNeedsStatusBarAppearanceUpdate()
    }
    
    func makeViewLight() {
    
        viewIsDark = false
        setNeedsStatusBarAppearanceUpdate()
    }
    
    override var preferredStatusBarStyle: UIStatusBarStyle {
    
        if viewIsDark {
            return .lightContent 
        } else {
            return .default 
        } 
    }
    

1
如果您在动画块内调用此方法,则更改将与动画块的其余部分一起进行动画处理。 - Alexandre G

25

您需要在Info.plist文件中添加以下密钥:

View controller-based status bar appearance,其布尔值设置为NO

在您的appdelegate类中,在didFinishLaunchingWithOptions方法中return之前。

let statusBar: UIView = UIApplication.shared.value(forKey: "statusBar") as! UIView
if statusBar.responds(to:#selector(setter: UIView.backgroundColor)) {
    statusBar.backgroundColor = UIColor.red
}
UIApplication.shared.statusBarStyle = .lightContent

根据需要更改backgroundColorstatusBarStyle


不错的解决方案,但这算使用私有 API 吗? - GoldenJoe
工作得很好,但我该如何更改为我的自定义颜色? - iSrinivasan27
@MohanSrinivasan,你可以指定自定义颜色,而不是使用“UIColor.red”。 - Himanshu padia

16

您也可以在storyboard中完成此操作

  1. 在info.plist中创建一个新的条目“视图控制器为基础的状态栏外观”,将其设置为“YES”。
  2. 进入您的Storyboard,然后选择要更改的导航控制器。从Storyboard文档大纲部分(Storyboard左侧面板)单击导航栏
  3. 进入右侧面板并单击属性部分
  4. 在导航栏部分下,您会看到样式。选择您想要的样式(默认为黑色和黑色为白色)

您需要为每个导航控制器执行此操作。但是,在该导航控制器下的任何视图都将更改所有视图的状态栏样式/颜色为您刚刚选择的样式。我认为这个选项更好,因为您可以立即查看结果,并且不必在每个视图控制器中添加额外的代码行。

输入图片说明

(使用Xcode 8.3.3在全Swift项目中完成)


“View controller-based status bar appearance” 应该设置为“NO”。 - Willjay
3
根据视图控制器内容设置状态栏样式的方法非常简洁,这是正确的做法,而不仅仅是设置“基于视图控制器的状态栏外观= NO”,并且在整个应用程序中只能使用浅色或深色样式。遗憾的是,这种“无代码”方法仅适用于导航控制器,苹果应该考虑在任何视图控制器实例内添加另一个字段来设置此选项。 - aldoram5

15

对于想要在iOS 11上为所有视图控制器更改状态栏的人,Swift 4/5的解决方案非常简单。

1) 在 Info.plist 中添加:

View controller-based status bar appearance -> NO

2) 在 XCode 的左侧选择项目 > Targets > 选择你的项目 > 在“通用”下选择“部署信息” > 选择状态栏样式:浅色。

如果你只想为一个视图控制器更改状态栏,在viewDidLoad中添加:

2.1) Info.plist

View controller-based status bar appearance -> YES

2.2)

override var preferredStatusBarStyle : UIStatusBarStyle {
    return .lightContent
}

Objective-C(或React Native)从App Delegate更改:

1)在Info.plist中添加:

View controller-based status bar appearance -> NO

2)AppDelegate -> didFinishLaunchingWithOptions

[[UIApplication sharedApplication] setStatusBarHidden:NO animated:YES];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleDarkContent animated:YES];

试图使用push(导航控制器)更改状态栏不起作用,只有在呈现模态视图控制器时才起作用。


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