旧项目如何在 SwiftUI 中控制状态栏的样式? —— Ficow 的实战笔记

| Swift , iOS , SwiftUI

 

内容概览

  • 前言
  • App 启动时隐藏状态栏
  • App 显示启动动画时,显示白色的状态栏
  • App 启动动画结束后,显示黑色的状态栏
  • 总结

 

前言

 

越来越多的 iOS 开发工程师在使用 SwiftUI 进行 iOS App 开发,旧的 UIKit 的玩法在慢慢地被抛弃。
然而,毕竟SwiftUI 还在逐步完善,在这个过程中有些需求我们还是需要借助UIKit来完成。这样做,既省时又省力。
比如,比较旧的 App (最低兼容版本低于 iOS 16) 只用 SwiftUI 改动状态栏的样式就会遇到一些问题,我们一起来看看如何处理吧。

Ficow 在这里为你提供一种实现思路,希望对你有所帮助~

 

App 启动时隐藏状态栏

 

找到项目的 Info.plist 文件,将 Status bar is initially hidden 设置为 YES

这一步,老老实实改配置文件就好了。

 

App 显示启动动画时,显示白色的状态栏

 

继续修改 Info.plist 文件,将 Status bar style 设置为 Light Content

这样,启动之后显示的状态栏就会默认是白色。

 

App 启动动画结束后,显示黑色的状态栏

 

这一步,也要先修改 Info.plist 文件,将 View controller-based status bar appearance 设置为 YES

然后,定义一个 SwiftUI 扩展,如下所示:

import SwiftUI
import UIKit

struct StatusBarStylePreferenceKey: PreferenceKey {
    static var defaultValue: UIStatusBarStyle = .darkContent

    static func reduce(value: inout UIStatusBarStyle, nextValue: () -> UIStatusBarStyle) {
        value = nextValue()
    }
}


extension View {
    func statusBarStyle(_ value: UIStatusBarStyle) -> some View {
        preference(key: StatusBarStylePreferenceKey.self, value: value)
    }
}

class RootViewController: UIHostingController<AnyView> {
    override init(rootView: AnyView) {
        weak var vc: RootViewController? = nil
        super.init(
            rootView: rootView
                .onPreferenceChange(StatusBarStylePreferenceKey.self) {
                    vc?.userPreferredStatusBarStyle = $0
                }.eraseToAnyView()
        )
        vc = self
    }

    @objc required dynamic init?(coder: NSCoder) {
        fatalError("required dynamic init not implemented")
    }

    override var preferredStatusBarStyle: UIStatusBarStyle {
        userPreferredStatusBarStyle
    }

    private var userPreferredStatusBarStyle: UIStatusBarStyle = .lightContent {
        didSet { setNeedsStatusBarAppearanceUpdate() }
    }
}

接下来,我们还需要将 window 的 rootViewController 从系统提供的 UIHostingController 换成 RootViewController 这个自定义子类。比如:

window?.rootViewController = RootViewController(rootView: HomePage())
window.makeKeyAndVisible()

最后,用上之前定义的 View 扩展方法即可:

struct HomePage: View {
    @State private var statusBarStyle = UIStatusBarStyle.lightContent

    var body: some View {
        ZStack() {
            // some subviews
        }
        .statusBarStyle(statusBarStyle)
    }
}

在启动动画结束的时候,将 statusBarStyle 改为 .darkContent 即可让状态栏变为黑色。

 

总结

 

在实现 SwiftUI 的过程中,总有这样那样的小问题出现,还好我们可以回退到 UIKit 实现。希望苹果能尽快完善 SwiftUI。

如果你的 App 比较新(iOS 16.0+),而且用到了 NavigationStack,可以考虑这个方案(亲测有效): Status bar color in iOS 16

 

参考内容:
How to dynamically hide the status bar and the home indicator in SwiftUI?
Status bar color in iOS 16

 

觉得不错?点个赞呗~

本文链接:旧项目如何在 SwiftUI 中控制状态栏的样式? —— Ficow 的实战笔记

转载声明:本站文章如无特别说明,皆为原创。转载请注明:Ficow Shen's Blog

评论区(期待你的留言)