As a patient with terminal obsessive-compulsive disorder, details like StatusBar cannot be let go. For each interface, StatusBar must display the correct style. And then there was this summary.

The original methods

There is a simple and crude way to achieve absolute control over StatusBar Style:

open func setStatusBarStyle(_ statusBarStyle: UIStatusBarStyle, animated: Bool)
Copy the code

This method has been around since the days of iOS 2.0 and allows you to set the StatusBar Style directly.

However, Apple has been doing its best to deprecate old apis, and unfortunately this method has been marked deprecated since iOS 9:

@available(iOS, introduced: 2.0, deprecated: 9.0, message: "Use -[UIViewController preferredStatusBarStyle]")
open func setStatusBarStyle(_ statusBarStyle: UIStatusBarStyle, animated: Bool)
Copy the code

If you want to continue managing StatusBar Style this way, you need to set the View Controller-based status bar appearance to NO in the info.plist file.

But the code is littered with deprecated warnings and additional Settings in info.plist that would be unacceptable for a terminally ill ocD sufferer; More importantly, deprecated means that the API will disappear without knowing when in the future. Burying such a mine in an App is really a pit, so the road is ruthlessly blocked.

A new direction

In fact, the setStatusBarStyle method was abolished is also expected, today’s programming ideas have been unknowingly advanced, ancient implementation-oriented programming ideas have been far from today’s protocol programming. Although the old method can solve the problem in a simple and rough way, it also leaves a lot of after-effects. For example, setting the Style of StatusBar directly in a complicated logic often causes confusion and ultimately does not get the desired effect. In addition, since we can change the StatusBar Style anywhere, in any code logic, this is often disastrous for later maintenance and ultimately more than worth the cost.

In fact, As early as iOS 7, Apple has kept pace with The Times to provide a new system for controlling Status Bar Style, that is, the View Controller-based Status Bar appearance above, By limiting the freedom to change the Status Bar Style, the View Controller is responsible for controlling the Status Bar Style in its own life cycle. This way, the whole idea becomes clearer and more elegant.

The basic way

It’s actually easier to work with the new system, just override the relevant properties in the ViewController:

override var preferredStatusBarStyle: UIStatusBarStyle {
	return .lightContent
}
Copy the code

During App running, the Style of the current StatusBar is always determined by the preferredStatusBarStyle property of the ViewController at the top of the UI. When we need to change the Style, only need in preferredStatusBarStyle calculation method returns the new Style attribute values, and then call setNeedsStatusBarAppearanceUpdate () method:

override var preferredStatusBarStyle: UIStatusBarStyle {
	if needsLightContent {
		return .lightContent
	} else {
		return .default}}private func changeStyle(a) {
	needsLightContent = true
	setNeedsStatusBarAppearanceUpdate()
}
Copy the code

In this mode, we always manage the Style of the Status Bar through the ViewController, and if we need to update its Status, we inform the ViewController indirectly, rather than directly changing the Status Bar’s properties. In this way, the later code maintenance work can also be easier.

Distribution control rights

If the top ViewController is just a shell, and the actual UI logic is controlled by the ChildViewController added to it, So this time you can rewrite childViewControllerForStatusBarStyle attribute, to distribute to the corresponding control of the Status Bar Style ChildViewController to:

override var childViewControllerForStatusBarStyle: UIViewController? {
	let currentChildViewController = childViewControllers[0]
	return currentChildViewController
}
Copy the code

A special case

Of course, the new mode also introduces new rules (KENG), and we encounter a new problem as we experience the new crude approach: what if different ViewControllers fight for control? For example, Navigation and Modal Presentation are two different things, they are typical representatives of one ViewController nested in another ViewController, who is in charge at this time?

If there is a hole, fill it, first take Navigation.

Navigation

When the top ViewController of the UI is nested inside the UINavigationController, The UINavigationController and the ContentViewController at the top of the stack both compete for control of the Status Bar. If not, the new order will be destroyed immediately, so we have the following rules:

  • The ContentViewController at the top of the stack manages the Style of the Status Bar when the Navigation Bar is not visible

  • The NavigationController is responsible for managing the Status Bar Style when the Navigation Bar is visible

    At this point, since the Navigation Bar is visible, the Status Bar needs to be consistent with the style of the Navigation Bar, So it makes most sense for the NavigationController to control the Status Bar Style.

    NavigationController uses the default UINavigationController class. What if the Status Bar Style does not meet your requirements? You can’t override the preferredStatusBarStyle property without inheriting UINavigationController; If you inherit from UINavigationController, you can do that, but you break the simplicity of your code, and Apple doesn’t recommend that you inherit from UINavigationController, And there are many system components are directly inherited from UINavigationController (such as MFMailComposeViewController), inheritance is only at this time, however, and there is no use. So what can be done about this problem?

It has to be, and Apple has thought about this for a long time, so it has done some work for the UINavigationBar by providing an entry point to set the Status Bar Style: the barStyle property. The barStyle attribute determines the appearance of the NavigationBar, so changing the barStyle attribute will change the Status Bar’s Style:

  • When barStyle =.default, NavigationBar is black and StatusBar is white

  • When barStyle =.black, NavigationBar is white and StatusBar is black

    If you set barTintColor to the color of the NavigationBar, you need to set the barStyle property to tell the NavigationController the correct Status Bar Style.

    Also note that, for some reason, the SettingsbarStyleAfter the changebarTintColor, so you need to modify it firstbarStyleProperty, and then setbarTintColor.

Modal Presentation

After knowing Navigation, the logic of Model Presentation is relatively simple. If the view presented by Modal Presentation is also nested in NavigationController, In this case, the rules are the same as described in Navigaion, otherwise the top ViewController also determines the Style of the Status Bar.

It should be noted that the logic of Modal Presentation has a >> prerequisite <<, only when the modalPresentationStyle attribute is.fullscreen, i.e., fullScreen Presentation, The rendered view has a say in the Status Bar Style, otherwise the original ViewController controls it.

However, everything has its own reason. If your obsessive-compulsive disorder has become incurable and you have to control the Style of the Status Bar in the ViewController of the incomplete Presentation, it is not impossible. ModalPresentationCapturesStatusBarAppearance is tailored specifically for obsessive-compulsive disorder patients, only need to rewrite this attribute and returns true, You gain control of the Status Bar Style in any Model Presentation.

conclusion

The UIStatusBar is a detail that most apps need to touch, but it’s also one of the most overlooked. We’ve seen a lot of apps (including some big companies) with abnormal status bars. Most of the time this represents a person, a team to do things, do the attitude of the product. I have always believed that software should be developed as a work of art, not as a product line, and that every detail should be taken care of. Instead of talking about algorithms and performance all day long, we should start from the details at hand, improve every user experience and eliminate bad apps.