SwiftUI:为特定视图设置状态栏颜色

时间:2020-01-02 20:17:50

标签: ios swift iphone swiftui

我一直试图为单个视图设置应用程序的状态栏颜色。

我尝试了此处列出的解决方案。.'How to change Status Bar text color in iOS',但这为整个应用程序设置了它。

我想要的是状态栏颜色,以便在SceneDelegate.swift中为rootViewController设置白色文本,然后将所有其他视图默认设置为默认(根据黑暗模式从白色更改为黑色)。

有什么想法吗?

1 个答案:

答案 0 :(得分:4)

可以基于每个视图控制器修改状态栏内容的颜色,但是SwiftUI通常仅使用一个视图控制器,即根宿主视图控制器。因此,它需要推动该根控制器来更改preferredStatusBarStyle属性,该属性在基类中是只读的。

因此,我们的想法是覆盖默认的UIHostingController来更改preferredStatusBarStyle值并使用自定义Environment值,以便任何内部SwiftUI子视图都可以修改该首选内容样式。

这是一种方法,草率的(假设目标Info.plist配置正确)

class LocalStatusBarStyle { // style proxy to be stored in Environment
    fileprivate var getter: () -> UIStatusBarStyle = { .default }
    fileprivate var setter: (UIStatusBarStyle) -> Void = {_ in}

    var currentStyle: UIStatusBarStyle {
        get { self.getter() }
        set { self.setter(newValue) }
    }
}

// Custom Environment key, as it is set once, it can be accessed from anywhere
// of SwiftUI view hierarchy
struct LocalStatusBarStyleKey: EnvironmentKey { 
    static let defaultValue: LocalStatusBarStyle = LocalStatusBarStyle()
}

extension EnvironmentValues { // Environment key path variable
    var localStatusBarStyle: LocalStatusBarStyle {
        get {
            return self[LocalStatusBarStyleKey.self]
        }
    }
}

// Custom hosting controller that update status bar style
class MyHostingController<Content>: UIHostingController<Content> where Content: View {
    private var internalStyle = UIStatusBarStyle.default

    @objc override dynamic open var preferredStatusBarStyle: UIStatusBarStyle {
        get {
            internalStyle
        }
        set {
            internalStyle = newValue
            self.setNeedsStatusBarAppearanceUpdate()
        }
    }

    override init(rootView: Content) {
        super.init(rootView:rootView)

        LocalStatusBarStyleKey.defaultValue.getter = { self.preferredStatusBarStyle }
        LocalStatusBarStyleKey.defaultValue.setter = { self.preferredStatusBarStyle = $0 }
    }

    @objc required dynamic init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

用法..

1)场景委托中的某个地方

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        ...
        window.rootViewController = MyHostingController(rootView: contentView)

2)在内容视图中的某处

struct ContentView: View {
    @Environment(\.localStatusBarStyle) var statusBarStyle

    ...
    var body: some View {
        ZStack {
           ....
            NavigationView {
                NavigationLink(destination:  ...) {
                    ...
                }
                .onAppear {
                    self.statusBarStyle.currentStyle = .lightContent
                }
                .onDisappear {
                     self.statusBarStyle.currentStyle = .default
                 }
            }
        }
    }
}