Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
214 views
in Technique[技术] by (71.8m points)

ios - SwiftUI: Set Status Bar Color For a Specific View

i have been trying to set the status bar colour of my application for just a single view.

i have tried the solution listed here..'How to change Status Bar text color in iOS' but that sets it for the whole application.

What i want is the status bar colour to have white text for the rootViewController set in SceneDelegate.swift and then be defaulted (change from white to black depending on dark mode) for all other views.

any ideas?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Status bar content color can be modified per view controller based, but SwiftUI uses, most usually, only one view controller, root hosting view controller. So it needs to push that root controller to change preferredStatusBarStyle property, which in base class is read-only.

So the idea is to override default UIHostingController to have possibility change that preferredStatusBarStyle value and use custom Environment value so any internal SwiftUI subview can modify that preferred content style.

Here is approach, scratchy, (it is assumed that target Info.plist is configured appropriately)

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

Usage..

1) somewhere in scene delegate

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

2) somewhere in content view

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...