首页 > 解决方案 > 如何在 SwiftUI 应用程序生命周期中更改 StatusBarStyle?

问题描述

我已经花了很多时间试图找出一种使用新生命周期SwiftUI App将statusBarStyle更改为亮/暗的方法。

关于状态栏的最新帖子教如何隐藏它,但我不想这样做,我只需将其更改为深色或浅色。

要更改颜色,我发现的最新方法是打开SceneDelegate.swift并更改window.rootViewController以使用我自己的HostingController,但它仅适用于使用UIKit App Delegate Lifecycle的项目。使用SwiftUI App LifecycleSceneDelegate.swift不会生成,那么我在哪里可以做到呢?

我可以通过 Xcode 界面上的常规设置来完成。我的问题是关于如何通过代码动态地做到这一点。

以下是我到目前为止所得到的。

一切.swift

import Foundation
import SwiftUI

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

struct LocalStatusBarStyleKey: EnvironmentKey {
    static let defaultValue: LocalStatusBarStyle = LocalStatusBarStyle()
}

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

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

struct TitlePage: View {
    @Environment(\.localStatusBarStyle) var statusBarStyle
    @State var title: String

    var body: some View {
        Text(title).onTapGesture {
            if self.statusBarStyle.currentStyle == .darkContent {
                self.statusBarStyle.currentStyle = .default
                self.title = "isDefault"
            } else {
                self.statusBarStyle.currentStyle = .darkContent
                self.title = "isDark"
            }
        }
    }
}

struct ContainerView: View {
    var controllers: [MyHostingController<TitlePage>]
    
    init(_ titles: [String]) {
        self.controllers = titles.map { MyHostingController(rootView: TitlePage(title: $0)) }
    }
    
    var body: some View {
        PageViewController(controllers: self.controllers)
    }
}

struct PageViewController: UIViewControllerRepresentable {
    var controllers: [UIViewController]
    
    func makeUIViewController(context: Context) -> UIPageViewController {
        let pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
        return pageViewController
    }
    
    func updateUIViewController(_ uiViewController: UIPageViewController, context: Context) {
        uiViewController.setViewControllers([controllers[0]], direction: .forward, animated: true)
    }
    
    typealias UIViewControllerType = UIPageViewController
}

MyApp.swift

import SwiftUI

@main
struct TestAppApp: App {
    var body: some Scene {
        WindowGroup {
            ContainerView(["Subscribe", "Comment"])
        }
    }
}

struct TestAppApp_Previews: PreviewProvider {
    static var previews: some View {
        Text("Hello, World!")
    }
}

在此处输入图像描述

标签: iosswiftcolorsswiftuistatusbar

解决方案


向 Info.plist 添加两个值:

<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string>

这适用于新的 SwiftUI 应用程序生命周期 (@main)。在 iOS14.4 上验证。

在此处输入图像描述


推荐阅读