Swift 如何设置状态栏样式 3

How to set Status Bar Style in Swift 3

我正在使用 Xcode 8.0 beta 4。

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

public func preferredStatusBarStyle() -> UIStatusBarStyle

但是,我发现它在 Swift 中变成了 "Get ONLY varaiable" 3.

public var preferredStatusBarStyle: UIStatusBarStyle { get } 

如何提供要在我的 UIViewController 中使用的样式?

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

 override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
}

如果您有条件地设置它,您将需要调用 setNeedsStatusBarAppearanceUpdate() 以便它在您准备好时以动画方式显示更改

这对我有用

在 plist 中将 View controller-based status bar 外观设置为 NO 然后在 UIViewController viewDidAppear 中添加以下行

UIApplication.shared.setStatusBarStyle(UIStatusBarStyle.lightContent, animated: true)

[更新] 对于 Xcode 10+ & Swift 4.2+

这是 iOS 7 及更高版本

的首选方法

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

覆盖每个视图控制器中的 preferredStatusBarStyle (Apple docs)。例如:

override var preferredStatusBarStyle: UIStatusBarStyle {     
      return .lightContent
}

如果您 preferredStatusBarStyle 根据视图控制器内部发生的变化(例如,滚动位置或显示的图像是否黑暗)返回不同的首选状态栏样式,那么您将想在状态改变时调用 setNeedsStatusBarAppearanceUpdate()

iOS 版本 7 之前,弃用方法

Apple has deprecated this,所以以后会去掉。使用上面的方法,下一个iOS版本发布时就不用重写了。

如果您的应用程序将支持在您的应用程序的 Info.plist 中,将 View controller-based status bar appearance 设置为 NO

appDelegate.swiftdidFinishLaunchingWithOptions函数中,添加:

UIApplication.shared.statusBarStyle = .lightContent

对于导航控制器

如果您使用导航控制器并且希望使用每个视图控制器的首选状态栏样式,请在应用程序的 info.plist[=29] 中将 View controller-based status bar appearance 设置为 YES =]

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

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.list 中添加行:查看 controller-based 状态栏外观 并将其设置为 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 
        } 
    }
    

第一步,您需要添加一行键:View controller-based status bar appearance 和值 NOInfo.plist 文件。之后,在您的控制器中添加 2 个函数,以指定仅该控制器会起作用:

override func viewWillAppear(_ animated: Bool) {
       super.viewWillAppear(animated)
       UIApplication.shared.statusBarStyle = .lightContent
}

override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        UIApplication.shared.statusBarStyle = .default    
}

如果要将 statusBar 的颜色更改为白色,对于 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

希望这对那些没有成功接受答案的人有所帮助!

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

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

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

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

Xcode8.3.1,Swift3.1

  1. 在 info.plist 中创建一个新条目 "View controller-based status bar appearance" 将其设置为 "NO"。

  2. 打开 AppDelegate.swift 并在 "didFinishLaunchingWithOptions" 方法中添加这些行:

application.statusBarStyle = .lightContent

swift 3

if View controller-based status bar appearance = YES in Info.plist

然后将此扩展用于所有 NavigationController

    extension UINavigationController
    {
        override open var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
         }
     }

如果没有 UINavigationController 而只有 UIViewController 那么使用下面的代码:

    extension UIViewController
    {
        override open var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
         }
     }

您也可以在情节提要中执行此操作

  1. 在 info.plist 中创建一个新条目 "View controller-based status bar appearance" 将其设置为 "YES"。
  2. 转到您的情节提要,然后 select 您要更改的导航控制器。单击故事板文档大纲部分的导航栏(故事板的左侧面板)
  3. 转到右侧面板并单击属性部分
  4. 在导航栏部分下,您将看到样式。 Select你喜欢的风格(默认为黑色,黑色为白色)

您必须为您拥有的每个导航控制器执行此操作。但是,该导航控制器下的任何视图都会将所有视图的状态栏 style/color 更改为您刚刚 select 编辑的状态栏。我发现这个选项更好,因为你可以立即看到你的结果,而不必在每个视图控制器中添加额外的代码行。

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

Swift 3

在 Info.plist 中添加一个名为 "View controller-based status bar appearance" 的行并将其值设置为 No.

class YourViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        UIApplication.shared.statusBarStyle = .lightContent //or .default
        setNeedsStatusBarAppearanceUpdate()

    }

}

Swift 3

要在您的应用中设置相同的导航栏外观,您可以在 AppDelegate.swift 中执行此操作:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        setupNavigationBarAppearence()
        return true
    }



private func setupNavigationBarAppearence(){
        let navigationBarAppearace = UINavigationBar.appearance()
        navigationBarAppearace.isTranslucent = false
        //nav bar color
        navigationBarAppearace.barTintColor = UIColor.primaryColor()
        //SETS navbar title string to white
        navigationBarAppearace.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
        //Makes the batery icon an any other icon of the device to white.
        navigationBarAppearace.barStyle = .black
    }

对于objective C,只需在您的应用程序 didFinishLaunch 方法中添加这一行

UIApplication.sharedApplication.statusBarStyle = UIStatusBarStyleLightContent;

Swift 4.0 请在 "didFinishLaunchingWithOptions launchOptions:" Appdelegate class

中使用此代码
UIApplication.shared.statusBarStyle = .lightContent
let statusBar: UIView = UIApplication.shared.value(forKey: "statusBar") as! UIView
if statusBar.responds(to: #selector(setter: UIView.backgroundColor)){
  statusBar.backgroundColor = UIColor.black
}

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

这篇文章原封不动地留给任何愿意了解过去几年出现的不同方法背后的逻辑的人。同时,从 Xcode 10 开始,Swift 4.2 first approach is deprecated 不再受支持(即 不会 如果你尝试使用它就会生效)。仍然参考它以供您更好地理解 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

这样,每当打开一个新的视图控制器时,如果您在每个需要的 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(),状态栏样式更改将被触发。

第三种方法——Hack!

有一个 hack 允许直接访问状态栏:

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

别无选择:开发人员应该让 each 视图控制器定义状态栏外观,方法是将标志设置为 YES(或省略此操作,因为默认情况下为 YES)并按照上述说明进行操作。


奖金

您可以(尽管不鼓励)在复杂情况下使用基于 Hack 的解决方案,以便在任何阶段自愿更改状态栏外观。在颜色方面,以下扩展方法完全可以用常规方法完成。您可以根据需要进行调整。

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

在处理导航栏时,状态栏文本颜色似乎有一个小问题。

如果您希望 .plist 条目基于视图控制器的状态栏外观设置为 YES,当您有彩色导航栏时它有时不起作用。

例如:

override func viewWillAppear(_ animated: Bool) {
    let nav = self.navigationController?.navigationBar
    nav?.barTintColor = .red
    nav?.tintColor = .white
    nav?.titleTextAttributes = [NSAttributedStringKey.foregroundColor: UIColor.white]
    setNeedsStatusBarAppearanceUpdate()
}

override var preferredStatusBarStyle: UIStatusBarStyle {return .lightContent}

即使您在 AppDelegate 中设置了以下内容,上面的代码也不会工作:

UIApplication.shared.statusBarStyle = .lightContent

对于那些仍在苦苦挣扎的人来说,显然它会以某种方式根据导航栏中的样式来判断状态栏是亮还是暗。因此,我设法通过在 viewWillAppear 中添加以下行来解决此问题:

nav?.barStyle = UIBarStyle.black

当条形样式为黑色时,它会监听您覆盖的变量。希望这对某人有帮助:)

Swift 4+

对于白色状态栏文本:

navigationController.navigationBar.barStyle = .blackTranslucent

iOS 11.2

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

    UINavigationBar.appearance().barStyle = .black

    return true
}

您可以使用名为 "shouldStatusBarDark" 的布尔值 属性 来切换状态栏颜色。您还可以更新其值以在滚动时更改状态栏颜色。

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

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

 func scrollViewDidScroll(_ scrollView: UIScrollView) {
     let offSetY = scrollView.contentOffset.y
     if offSetY > 50 {
         UIView.animate(withDuration: 0.4, animations: {
             self.navView.alpha = 1
             self.shouldStatusBarDark = true
         })
     } else {
         UIView.animate(withDuration: 0.4, animations: {
             self.navView.alpha = 0
             self.shouldStatusBarDark = false
         })
     }
 }

这里是Apple Guidelines/Instruction关于状态栏样式的改变。

如果你想设置状态栏样式,应用级别然后在你的.plist文件中设置UIViewControllerBasedStatusBarAppearanceNO。并在您的 appdelegate > didFinishLaunchingWithOptions 添加以下 ine(您可以通过应用程序委托以编程方式完成)。

Objective C

[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];

Swift

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

如果您想在视图控制器级别设置状态栏样式,请按照以下步骤操作:

  1. 如果您只需要在 UIViewController 级别设置状态栏样式,请在 .plist 文件中将 UIViewControllerBasedStatusBarAppearance 设置为 YES
  2. 在viewDidLoad中添加函数——setNeedsStatusBarAppearanceUpdate

  3. 在您的视图控制器中覆盖 preferredStatusBarStyle。

Objective C

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self setNeedsStatusBarAppearanceUpdate];
}

- (UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}

Swift

override func viewDidLoad() {
    super.viewDidLoad()
    self.setNeedsStatusBarAppearanceUpdate()
}

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
}

根据状态栏样式设置级别设置.plist的值。

使用 WebkitView

Swift9.3iOS11.3

import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate, WKUIDelegate {

    @IBOutlet weak var webView: WKWebView!
    var hideStatusBar = true

    override func loadView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.setNeedsStatusBarAppearanceUpdate()
        let myURL = URL(string: "https://www.apple.com/")
        let myRequest = URLRequest(url: myURL!)
        UIApplication.shared.statusBarView?.backgroundColor = UIColor.red

         webView.load(myRequest)

    }
}

extension UIApplication {

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

}

这些答案中的大多数都是经过重新哈希处理的相同内容,但其中 none 实际上在使用深色背景时为我解决了启动屏幕问题。

我在我的 info.plist 中使用以下方法解决了这个问题,它生成了一个浅色状态栏。

<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>

对于希望更改所有 viewcontroller 状态栏的人:iOS 11,Swfit 4/5 解决方案非常简单。

1) Info.plist 添加:

View controller-based status bar appearance -> NO

2) XCode 左侧选择项目 > Targets > Select 你的项目 > 在常规下> 部署信息 > Select 状态栏样式:浅色

如果您只想更改 一个 viewcontroller 的状态栏,请在 viewDidLoad 上添加:

2.1) Info.plist

View controller-based status bar appearance -> YES

2.2)

override var preferredStatusBarStyle : UIStatusBarStyle {
    return .lightContent
}

Objective-C(或反应本机)从 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];

更改状态栏 不起作用 尝试推送(导航控制器),仅在模态呈现时 viewcontrollers.

添加到@Krunal 的精彩回答

如果您使用 UINavigationControllerpreferredStatusBarStyle 将不会影响 UIViewController

Xcode 10 和 Swift 4.

设置自定义UINavigationController

示例:

class LightNavigationController: UINavigationController {

   open override var preferredStatusBarStyle: UIStatusBarStyle {
       return .lightContent
   }
}

为应用级解决方案使用扩展:

extension UINavigationController {

  open override var preferredStatusBarStyle: UIStatusBarStyle {
      guard let index = tabBarController?.selectedIndex else { return .default }
      switch index {
      case 0, 1, 2: return .lightContent // set lightContent for tabs 0-2
      default: return .default // set dark for tab 3
      }
  }
}

如果您收到警告:'statusBarStyle' 的 Setter 在 iOS 9.0 中已弃用:使用 -[UIViewController preferredStatusBarStyle],然后使用以下代码将状态栏设置为浅色或深色:

//To set the status bar to white
self.navigationController?.navigationBar.barStyle = .black //or .blackTranslucent

//To set the status bar to black
self.navigationController?.navigationBar.barStyle = .default

这不会使您的导航栏发生变化,它纯粹表示样式,因此会相应地更改状态栏。

注意。您需要确保在 info.plist.

中设置
View controller-based status bar appearance to YES

Xcode 10 或更高

在 Swift 5

中测试

无需代码,只需按照以下步骤操作即可。

If you want to change the status bar in the whole app.

  1. Select 来自项目导航器(左侧面板)的项目。
  2. Select目标。
  3. Select 常规选项卡。
  4. 查找部署信息。
  5. 将状态栏样式更改为 浅色(深色背景 “浅色”,浅色背景 “默认”)

不要忘记 info.plist 变化

  1. Select 信息选项卡
  2. 将此密钥添加到您的 plist 文件中“查看 controller-based 状态栏外观”= NO

运行 你的项目并检查它。

我的项目在 swift 5 和 Xcode 10.2 和 11.0

如果您使用模态显示,您需要设置:

viewController.modalPresentationCapturesStatusBarAppearance = true

在iOS13中可以使用.darkContentUIStatusBarStyle属性显示暗状态栏

如果按照上述方法仍然无法更改状态栏样式

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
}

你可以试试这个方法:

override viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    navigationController?.navigationBar.barStyle = .black
}

Swift 5

要在 上为 PRAVEEN 的 回答添加更多详细信息,我想提供我的实现。它支持灵活自定义每个控制器的状态栏。

总的来说,我们将创建一个 BaseViewController 来处理所有情况下的 statusBarStyle 属性。当您创建一个新控制器时,将其作为该基控制器的子类。

任何时候你想改变状态外观,你只需要更新这个属性。 状态栏样式会立即更新

实施

class BaseViewController: UIViewController {

    var statusBarStyle: UIStatusBarStyle = .default {
        didSet {
            setNeedsStatusBarAppearanceUpdate()
        }
    }

    override var preferredStatusBarStyle: UIStatusBarStyle {
        return statusBarStyle
    }
}

演示

class ViewController: BaseViewController, UIScrollViewDelegate {

    let scrollView = UIScrollView()
    ... 
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        UIView.animate(withDuration: 0.3) {
            if scrollView.contentOffset.y > 30 {
                self.statusBarStyle = .darkContent
            } else {
                self.statusBarStyle = .lightContent
            }
        }
    }
}

2。 UINavigationController

对于UINavigationController,这是一个特例,您可以按照以下任一解决方案:

解决方案 A:使用消息调度覆盖

由于 UINavigationController 是一个 NSObject 并继承自 ObjectiveC,其方法是 message dispatch,您可以覆盖它们。

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

解决方案 B:创建 UINavigationController 子类

如果您已经有一个自定义UINavigationController(通常需要控制更多的要求),这是最适合您的解决方案。

final class NavigationController: UINavigationController {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return topViewController?.preferredStatusBarStyle ?? super.preferredStatusBarStyle
    }
}
  1. 选择浅色内容

  2. 添加 查看 controller-based 状态栏外观 NO.plist

我也为此苦苦挣扎,所以如果您要呈现全屏模态视图控制器,请确保将 .modalPresentationStyle 设置为 .fullscreen 然后,在您呈现的视图控制器上,只需覆盖 .preferredStatusBarStyle.lightContent.

所以:

let navigationController = UINavigationController(rootViewController: viewController)
navigationController.modalPresentationStyle = .fullScreen // <=== make sure to set navigation modal presentation style
present(navigationController, animated: true, completion: nil)

在您的自定义视图控制器上,覆盖状态栏样式:

    override var preferredStatusBarStyle: UIStatusBarStyle {
        .lightContent
    }