【问题标题】:SwiftUI: Set Status Bar Color For a Specific ViewSwiftUI:为特定视图设置状态栏颜色
【发布时间】:2020-04-21 11:34:33
【问题描述】:

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

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

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

有什么想法吗?

【问题讨论】:

    标签: ios swift iphone swiftui


    【解决方案1】:

    状态栏内容的颜色可以根据每个视图控制器进行修改,但 SwiftUI 通常只使用一个视图控制器,即根托管视图控制器。所以它需要推动那个根控制器来改变preferredStatusBarStyle 属性,它在基类中是只读的。

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

    这里是方法,scratch,(假设目标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
                     }
                }
            }
        }
    }
    

    【讨论】:

    • 这有明显的延迟,但确实有效。目前我已将 Info.plist 中的用户界面样式设置为 Light。
    • 对于延迟问题,您可以创建一个 onWillDisappear ViewModifier。见stackoverflow.com/a/65875968/13509092
    • 请添加iOS14 SwiftUI应用生命周期代码示例。谢谢。
    猜你喜欢
    • 2022-11-11
    • 1970-01-01
    • 2019-11-25
    • 1970-01-01
    • 1970-01-01
    • 2016-12-22
    • 2020-03-19
    • 2016-03-30
    • 1970-01-01
    相关资源
    最近更新 更多