【问题标题】:SwiftUI: Status bar colorSwiftUI:状态栏颜色
【发布时间】:2019-11-25 12:53:52
【问题描述】:

有没有办法将 SwiftUI 视图的状态栏更改为白色?

我可能遗漏了一些简单的东西,但我似乎找不到在 SwiftUI 中将状态栏更改为白色的方法。到目前为止,我只看到.statusBar(hidden: Bool)

【问题讨论】:

  • 你是指状态栏背景还是状态栏文字?
  • 状态栏文字,切换到灯光样式
  • 您是要为整个应用更改它还是只为一个视图更改它?
  • 整个应用程序都可以,但知道如何只更改一个视图会很高兴

标签: ios swift swiftui


【解决方案1】:

通过使用.preferredColorScheme(_ colorScheme: ColorScheme?) 设置View.dark.light 模式配色方案,可以将状态栏文本/色调/前景色设置为白色。

层次结构中使用此方法的第一个视图将优先。

例如:

var body: some View {
  ZStack { ... }
  .preferredColorScheme(.dark) // white tint on status bar
}
var body: some View {
  ZStack { ... }
  .preferredColorScheme(.light) // black tint on status bar
}

【讨论】:

  • 谢谢。这是真正的 SwiftUI 方式。
  • 我相信这会完全改变配色方案,而不仅仅是状态栏文本颜色。如果您的应用使用深色主题,那么这不是一个可行的解决方案
  • 很好的答案,但它可能会导致更多的麻烦,因为这也会改变堆栈内列表和其他对象的配色方案。仅更改 UIStatusBar 将避免这种情况,并且在技术上减少代码。
【解决方案2】:

在链接到我编辑的 cmets this question here

但是要回答这个问题并帮助人们直接找到答案:

Swift 5 和 SwiftUI

为 SwiftUI 创建一个名为 HostingController.swift 的新 swift 文件

import SwiftUI

class HostingController<ContentView>: UIHostingController<ContentView> where ContentView : View {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
}

然后在 SceneDelegate.swift 中更改以下代码行

window.rootViewController = UIHostingController(rootView: ContentView())

window.rootViewController = HostingController(rootView: ContentView())

【讨论】:

  • 无论如何要从 SwiftUI 更改状态栏颜色? IE。如果您显示需要不同状态栏的模式?
  • 有了这个我想你需要记住暗模式可能需要影响这个值
  • 如果你有环境对象,这不起作用。
  • @RichardWitherspoon 我已经发布了一个新的答案,其中包含环境对象的有效解决方案
  • 新的 SwiftUI 生命周期呢?
【解决方案3】:

在info.plist中,你可以简单地设置

  • “状态栏样式”改为“轻量级内容”
  • “查看基于控制器的状态栏外观”为否

无需对代码进行任何更改...

【讨论】:

  • 似乎对 SwiftUI 应用没有任何作用。
  • @boxed 确保将“UIViewControllerBasedStatusBarAppearance”也设置为“NO”,否则 SwiftUI 可能会覆盖。
【解决方案4】:

只需将其添加到 info.plist

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

在 IOS 14、xcode 12 上测试

【讨论】:

  • 这是一个视频,展示了如何更新 info.plist youtu.be/w-I5I8POMSI
  • 伙计,你救了我的命
【解决方案5】:

现有答案涵盖了您只想更改一次状态栏颜色的情况(例如,在整个应用程序中使用浅色内容),但如果您想以编程方式执行此操作,则首选项键是实现此目的的一种方法。

可以在下面找到完整的示例,但这里是对我们将要做的事情的描述:

  • 定义一个符合PreferenceKey 的结构,Views 将使用它来设置他们喜欢的状态栏样式
  • 创建UIHostingController 的子类,它可以检测偏好更改并将它们桥接到相关的 UIKit 代码
  • 添加扩展 View 以获得几乎看起来是官方的 API

偏好键一致性

struct StatusBarStyleKey: PreferenceKey {
  static var defaultValue: UIStatusBarStyle = .default
  
  static func reduce(value: inout UIStatusBarStyle, nextValue: () -> UIStatusBarStyle) {
    value = nextValue()
  }
}

UIHostingController 子类

class HostingController: UIHostingController<AnyView> {
  var statusBarStyle = UIStatusBarStyle.default

  //UIKit seems to observe changes on this, perhaps with KVO?
  //In any case, I found changing `statusBarStyle` was sufficient
  //and no other method calls were needed to force the status bar to update
  override var preferredStatusBarStyle: UIStatusBarStyle {
    statusBarStyle
  }

  init<T: View>(wrappedView: T) {
// This observer is necessary to break a dependency cycle - without it 
// onPreferenceChange would need to use self but self can't be used until 
// super.init is called, which can't be done until after onPreferenceChange is set up etc.
    let observer = Observer()

    let observedView = AnyView(wrappedView.onPreferenceChange(StatusBarStyleKey.self) { style in
      observer.value?.statusBarStyle = style
    })

    super.init(rootView: observedView)
    observer.value = self
  }

  private class Observer {
    weak var value: HostingController?
    init() {}
  }

  @available(*, unavailable) required init?(coder aDecoder: NSCoder) {
    // We aren't using storyboards, so this is unnecessary
    fatalError("Unavailable")
  }
}

查看扩展

extension View {
  func statusBar(style: UIStatusBarStyle) -> some View {
    preference(key: StatusBarStyleKey.self, value: style)
  }
}

用法

首先,在您的 SceneDelegate 中,您需要将 UIHostingController 替换为您的子类:

//Previously: window.rootViewController = UIHostingController(rootView: rootView)
window.rootViewController = HostingController(wrappedView: rootView)

现在任何视图都可以使用您的扩展来指定他们的偏好:

VStack {
   Text("Something")
}.statusBar(style: .lightContent)

注意事项

this answer 对另一个问题提出了使用 HostingController 子类来观察偏好键变化的解决方案 - 我之前使用过有很多缺点的 @EnvironmentObject,偏好键似乎更适合这个问题。

这是解决此问题的正确方法吗?我不知道。可能存在无法处理的边缘情况,例如,如果层次结构中的多个视图指定了首选项键,我还没有彻底测试以查看哪个视图获得优先级。在我自己的使用中,我有两个相互排斥的视图,它们指定了它们首选的状态栏样式,所以我不必处理这个问题。因此,您可能需要对其进行修改以满足您的需要(例如,可能使用一个元组来指定样式和优先级,然后让您的 HostingController 在覆盖之前检查它的先前优先级)。

【讨论】:

  • 当您在每个下一个屏幕上都有不同样式的栏状态时,此解决方案最有价值。
  • 你需要告诉appkit这个值已经改变了let observedView = AnyView(rootView.onPreferenceChange(StatusBarStyleKey.self) { style in observer.value?.statusBarStyle = style observer.value?.setNeedsStatusBarAppearanceUpdate() })
  • @KlajdDeda 在我不需要的实验中,我认为 AppKit 正在使用一些 KVO 来确定已经进行了更改。也就是说,我已经发现这里描述的方法存在一些限制——特别是 SwiftUI 中的偏好从最浅到最深的视图应用,浅视图的偏好具有更高的优先级。因此,如果您的根视图更喜欢浅色内容,而更深层次的视图更喜欢深色内容,那么根视图将“获胜”。我不知道解决这个问题的好方法。
  • @Arkcann 谢谢你的回答帮助了我。我认为您可以在 PreferenceKey.reduce 方法中定义自定义逻辑,使其随心所欲。如果您希望更深层次的值优先,您可以将值附加到数组并仅使用第一项(或最后一项)。
  • 这适用于仍在使用 UIKit 应用程序生命周期的应用程序。你有使用新的 SwiftUI App main 的应用解决方案吗?
【解决方案6】:

仅限 SwiftUI 1 和 2!

创建一个主机控制器DarkHostingController 并在其上设置preferredStatusBarStyle

class DarkHostingController<ContentView> : UIHostingController<ContentView> where ContentView : View {
    override dynamic open var preferredStatusBarStyle: UIStatusBarStyle {
        .lightContent
    }
}

并包含SceneDelegate:

window.rootViewController = DarkHostingController(rootView: ContentView())

【讨论】:

  • 这适用于将文本颜色从黑色更改为白色,但如何更改状态栏的背景颜色?
  • @MobileMon 您使用 .edgesIgnoringSafeArea(.top) 让您的背景一直到顶部,您可以设置该颜色。你把它直接放在视图上。
  • 什么是“Model()”?你没有定义它。
  • @RichardWitherspoon 模型是我的数据模型对象,您不需要它用于此解决方案。我会删除它,以防止混淆。
  • 我喜欢使用泛型将 Controller 与特定类型分离(不像在投票最多的答案中所做的那样),但是,使用 '@objc' 和 'dynamic在这个特定的用例中打开'?
【解决方案7】:

此解决方案适用于使用新的 SwiftUI 生命周期的应用:

我需要动态更改状态栏文本,但无法访问 window.rootViewController,因为 SwiftUI 生命周期中不存在 SceneDelegate

我终于找到了 Xavier Donnellon 的这个简单的解决方案:https://github.com/xavierdonnellon/swiftui-statusbarstyle

StatusBarController.swift 文件复制到您的项目中,并将您的主视图包装到RootView

@main
struct ProjectApp: App {     
    var body: some Scene {
        WindowGroup {
            //wrap main view in RootView
            RootView {
                //Put the view you want your app to present here
                ContentView()
                    //add necessary environment objects here 
            }
        }
    }
}

然后您可以使用.statusBarStyle(.darkContent).statusBarStyle(.lightContent) 视图修饰符或调用例如直接UIApplication.setStatusBarStyle(.lightContent)

不要忘记在 Info.plist 中将“基于控制器的状态栏外观”设置为“YES”。

【讨论】:

  • 这是唯一对我有用的 SwiftUI 生命周期应用程序。感谢分享!
  • 警告:这会破坏 iOS15 中的 onOpenURL
  • 对我来说,我不需要在 Info.plist 中将“基于视图控制器的状态栏外观”设置为“YES”。
  • 使用此解决方案运行我的应用程序时,我在控制台中收到错误 Unbalanced calls to begin/end appearance transitions for &lt;_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x14cf0e3a0&gt;.。有谁知道如何解决这个问题?
  • 这适用于我的 iOS 14 设备,但在 iOS 15 中,它不会将状态栏更改应用于 fullScreenCover 内的视图。相反,它会在 fullScreenCover 内返回到亮模式或暗模式的默认状态栏样式,并且只有在 fullScreenCover 被解除后才返回使用我选择的样式。
【解决方案8】:

这对我有用。将这些行添加到您的 info.plist 文件中。 您需要切换顶部设置 (View controller-based status bar appearance) 以确定您要查找的内容。

【讨论】:

  • 哇,这确实有效,而且代码更少,并且适用于新的 SwiftUI 生命周期。就是这样!
【解决方案9】:

创建一个名为HostingController的新类:

import SwiftUI

final class HostingController<T: View>: UIHostingController<T> {
    override var preferredStatusBarStyle: UIStatusBarStyle {
        .lightContent
    }
}

在您的SceneDelegate.swift 中,将所有出现的UIHostingController 替换为HostingController

【讨论】:

    【解决方案10】:

    更新:看起来 Hannes Sverrisson 上面的答案是最接近的,但我们的答案略有不同。

    上面写的 UIHostingController 子类的答案在 XCode 11.3.1 中不起作用。

    对于子类(也处理 ContentView 环境设置),以下对我有用:

    import SwiftUI
    
    class HostingController<Content>: UIHostingController<Content> where Content : View {
        override var preferredStatusBarStyle: UIStatusBarStyle {
            return .lightContent
        }
    }
    

    然后在 SceneDelegate.swift 中,更改 window.rootViewController 设置确实有效:

    window.rootViewController = HostingController(rootView: contentView)
    

    【讨论】:

      【解决方案11】:

      @Dan Sandland 的回答对我有用,但在我的情况下,需要将界面保持在 .light 模式

      ZStack {
          Rectangle()...
          
          VStack(spacing: 0) {
              ...
          }.colorScheme(.light)
      }
      .preferredColorScheme(.dark)
      

      【讨论】:

        【解决方案12】:

        如果您使用environmentObject,您可以使用this answer 中提出的解决方案。

        新建一个文件并粘贴以下代码

        import SwiftUI
        
        class HostingController: UIHostingController<AnyView> {
           override var preferredStatusBarStyle: UIStatusBarStyle {
              return .lightContent
           }
        }
        

        这里的区别是我们使用AnyView而不是ContentView,这允许我们替换这个:

        window.rootViewController = UIHostingController(rootView:contentView.environmentObject(settings))
        

        通过这个:

        window.rootViewController = HostingController(rootView: AnyView(contentView.environmentObject(settings)))
        

        【讨论】:

        • 性能如何?我看到有人提到使用 AnyView 会对性能产生负面影响。
        • 我的应用并不重,所以我没有发现任何差异,但我无法确认是否有更重的应用
        【解决方案13】:

        上述解决方案适用于状态栏样式。如果要为状态栏应用背景颜色,则需要使用忽略顶部保存区域的 VStack。

            GeometryReader{geometry in
                VStack{
                    Rectangle().frame(width: geometry.size.width, height: 20, alignment: .center).foregroundColor(.red)
                    Spacer()
                    Your content view goes here
                }
                .frame(width: geometry.size.width, height: geometry.size.height)
            }.edgesIgnoringSafeArea(.top)
        

        您可以使用实际的状态栏高度而不是固定的 20。请参考下面的链接获取状态栏高度。 Status bar height in Swift

        【讨论】:

          【解决方案14】:

          我正在使用类似的东西

          extension UIApplication {
          
              enum ColorMode {
                  case dark, light
              }
          
              class func setStatusBarTextColor(_ mode: ColorMode) {
                  if #available(iOS 13.0, *) {
                      var style: UIUserInterfaceStyle
                      switch mode {
                      case .dark:
                          style = .dark
                      default:
                          style = .light
                      }
                      if let window = Self.activeSceneDelegate?.window as? UIWindow {
                          window.overrideUserInterfaceStyle = style
                          window.setNeedsDisplay()
                      }
                  }
              }
          
              class var activeSceneDelegate: UIWindowSceneDelegate? {
                  (Self.activeScene)?.delegate as? UIWindowSceneDelegate
              }
          }
          

          【讨论】:

          • 错误:类型“Self”没有成员“activeScene”。也请与我们分享您的 UIApplication 扩展。谢谢。
          【解决方案15】:

          Arkcann's answer 很棒,但不幸的是对我不起作用,因为 StatusBarStyleKey.defaultValue 占据了优先地位(我想知道他是如何做到的)。我将其设为Optional 并仅在显式设置时才覆盖先前设置的值。 (我是在 iOS 14.3 的真机上测试)

          struct StatusBarStyleKey: PreferenceKey {
            static func reduce(value: inout UIStatusBarStyle?, nextValue: () -> UIStatusBarStyle?) {
              guard let v = nextValue() else {
                return
              }
              
              value = v
            }
          }
          
          extension View {
            func statusBar(style: UIStatusBarStyle?) -> some View {
              return preference(key: StatusBarStyleKey.self, value: style)
            }
          }
          

          我在创建HostingController 时也采取了一些不同的方法,我将状态栏样式存储在全局范围内。

          private var appStatusBarStyle: UIStatusBarStyle?
          
          private class HostingController<ContentView: View>: UIHostingController<ContentView> {
            override var preferredStatusBarStyle: UIStatusBarStyle {
              return appStatusBarStyle ?? .default
            }
          }
          
          
          func createHostingController<T: View>(rootView :T) -> UIViewController {
            let view = rootView.onPreferenceChange(StatusBarStyleKey.self) {
              appStatusBarStyle = $0
            }
            
            return HostingController(rootView: view)
          }
          

          用法:

          window.rootViewController = createHostingController(rootView: MyApp())
          

          【讨论】:

            【解决方案16】:
            1. 为通知创建枚举(或任何您喜欢的用户):
                enum NotificationCenterEnum: String {
            
                     case changeStatusToDark
                     case changeStatusToLight
                        
                     var notification: Notification.Name {
                           return Notification.Name(self.rawValue)
                         }
                      }
            
            1. 创建自定义 HostingController
            class HostingController<Content: View>: UIHostingController<Content>  {
            
                override init(rootView: Content) {
                    super.init(rootView: rootView)
                    
                    NotificationCenter.default.addObserver(forName: NotificationCenterEnum.changeStatusToDark.notification, object: nil, queue: .main) { _ in self.statusBarEnterDarkBackground() }
              
                    NotificationCenter.default.addObserver(forName: NotificationCenterEnum.changeStatusToLight.notification, object: nil, queue: .main) { _ in self.statusBarEnterLightBackground() }
                }
                
                @objc required dynamic init?(coder aDecoder: NSCoder) {
                    fatalError("init(coder:) has not been implemented")
                }
                
                var isDarkContent = true
                
                func statusBarEnterLightBackground() {
                    isDarkContent = false
                    UIView.animate(withDuration: 0.3) {[weak self] in
                        self?.setNeedsStatusBarAppearanceUpdate()
                    }
                }
                
                func statusBarEnterDarkBackground() {
                    isDarkContent = true
                    UIView.animate(withDuration: 0.3) {[weak self] in
                        self?.setNeedsStatusBarAppearanceUpdate()
                    }
                }
                
                override var preferredStatusBarStyle: UIStatusBarStyle {
                    if isDarkContent {
                        return .lightContent
                    } else {
                        return .darkContent
                    }
                }
            }
            
            1. 在场景代理中

              window.rootViewController = HostingController(rootView: ContentView())

            2. 鉴于您有选择:

            A.如果您只需要一个视图,请使用 .onAppear/.onDisappear。

                .onAppear { NotificationCenter.default.post(name: NotificationCenterEnum.changeStatusToLight.notification, object: nil)
                            }
                .onDisappear { NotificationCenter.default.post(name: NotificationCenterEnum.changeStatusToDark.notification, object: nil)
                            }
            

            B.如果您需要多个视图一个接一个:像在 A 中一样使用 .onAppear,但在 backAction 上触发更改:

                private func backAction() {
                        NotificationCenter.default.post(name: NotificationCenterEnum.changeStatusToDark.notification, object: nil)
                        presentation.wrappedValue.dismiss()
                    }
            

            C.你可以像这样创建修饰符:

                struct StatusBarModifier: ViewModifier {
                    
                    func body(content: Content) -> some View {
                        content
                            .onAppear { NotificationCenter.default.post(name: NotificationCenterEnum.changeStatusToLight.notification, object: nil)
                            }
                            .onDisappear { NotificationCenter.default.post(name: NotificationCenterEnum.changeStatusToDark.notification, object: nil)
                            }
                    }
                }
            

            并使用它:

                .modifier(StatusBarModifier())
            

            【讨论】:

              【解决方案17】:

              静态(仅适用于使用旧的 UIWindowSceneDelegate 生命周期的项目)和动态替换键窗口的 UIHostingController 都会产生不良副作用(例如 onOpenURL 中断)。

              这是一种不同的方法,它涉及将preferredStatusBarStyle 转换为指向计算变量。

              extension UIViewController {
                  fileprivate enum Holder {
                      static var statusBarStyleStack: [UIStatusBarStyle] = .init()
                  }
              
                  fileprivate func interpose() -> Bool {
                      let sel1: Selector = #selector(
                          getter: preferredStatusBarStyle
                      )
                      let sel2: Selector = #selector(
                          getter: preferredStatusBarStyleModified
                      )
              
                      let original = class_getInstanceMethod(Self.self, sel1)
                      let new = class_getInstanceMethod(Self.self, sel2)
              
                      if let original = original, let new = new {
                          method_exchangeImplementations(original, new)
              
                          return true
                      }
              
                      return false
                  }
              
                  @objc dynamic var preferredStatusBarStyleModified: UIStatusBarStyle {
                      Holder.statusBarStyleStack.last ?? .default
                  }
              }
              

              通过一些额外的脚手架,这可用于实现 .statusBarStyle 视图修饰符。

              enum Interposed {
                  case pending
                  case successful
                  case failed
              }
              
              struct InterposedKey: EnvironmentKey {
                  static let defaultValue: Interposed = .pending
              }
              
              extension EnvironmentValues {
                  fileprivate(set) var interposed: Interposed {
                      get { self[InterposedKey.self] }
                      set { self[InterposedKey.self] = newValue }
                  }
              }
              
              /// `UIApplication.keyWindow` is deprecated
              extension UIApplication {
                  var keyWindow: UIWindow? {
                      connectedScenes
                          .compactMap { $0 as? UIWindowScene }
                          .flatMap(\.windows)
                          .first {
                              $0.isKeyWindow
                          }
                  }
              }
              
              extension UIViewController {
                  fileprivate enum Holder {
                      static var statusBarStyleStack: [UIStatusBarStyle] = .init()
                  }
              
                  fileprivate func interpose() -> Bool {
                      let sel1: Selector = #selector(
                          getter: preferredStatusBarStyle
                      )
                      let sel2: Selector = #selector(
                          getter: preferredStatusBarStyleModified
                      )
              
                      let original = class_getInstanceMethod(Self.self, sel1)
                      let new = class_getInstanceMethod(Self.self, sel2)
              
                      if let original = original, let new = new {
                          method_exchangeImplementations(original, new)
              
                          return true
                      }
              
                      return false
                  }
              
                  @objc dynamic var preferredStatusBarStyleModified: UIStatusBarStyle {
                      Holder.statusBarStyleStack.last ?? .default
                  }
              }
              
              struct StatusBarStyle: ViewModifier {
                  @Environment(\.interposed) private var interposed
              
                  let statusBarStyle: UIStatusBarStyle
                  let animationDuration: TimeInterval
              
                  private func setStatusBarStyle(_ statusBarStyle: UIStatusBarStyle) {
                      UIViewController.Holder.statusBarStyleStack.append(statusBarStyle)
              
                      UIView.animate(withDuration: animationDuration) {
                          UIApplication.shared.keyWindow?.rootViewController?.setNeedsStatusBarAppearanceUpdate()
                      }
                  }
              
                  func body(content: Content) -> some View {
                      content
                          .onAppear {
                              setStatusBarStyle(statusBarStyle)
                          }
                          .onChange(of: statusBarStyle) {
                              setStatusBarStyle($0)
                              UIViewController.Holder.statusBarStyleStack.removeFirst(1)
                          }
                          .onDisappear {
                              UIViewController.Holder.statusBarStyleStack.removeFirst(1)
              
                              UIView.animate(withDuration: animationDuration) {
                                  UIApplication.shared.keyWindow?.rootViewController?.setNeedsStatusBarAppearanceUpdate()
                              }
                          }
                          // Interposing might still be pending on initial render
                          .onChange(of: interposed) { _ in
                              UIView.animate(withDuration: animationDuration) {
                                  UIApplication.shared.keyWindow?.rootViewController?.setNeedsStatusBarAppearanceUpdate()
                              }
                          }
                  }
              }
              
              extension View {
                  func statusBarStyle(
                      _ statusBarStyle: UIStatusBarStyle,
                      animationDuration: TimeInterval = 0.3
                  ) -> some View {
                      modifier(StatusBarStyle(statusBarStyle: statusBarStyle, animationDuration: animationDuration))
                  }
              }
              
              
              @main
              struct YourApp: App {
                  @Environment(\.scenePhase) private var scenePhase
              
                  /// Ensures that interposing only occurs once
                  private var interposeLock = NSLock()
              
                  @State private var interposed: Interposed = .pending
              
                  var body: some Scene {
                      WindowGroup {
                          VStack {
                              Text("Hello, world!")
                                  .padding()
                          }
                          .statusBarStyle(.lightContent)
                          .environment(\.interposed, interposed)
                      }
                      .onChange(of: scenePhase) { phase in
                          /// `keyWindow` isn't set before first `scenePhase` transition
                          if case .active = phase {
                              interposeLock.lock()
                              if case .pending = interposed,
                                 case true = UIApplication.shared.keyWindow?.rootViewController?.interpose() {
                                  interposed = .successful
                              } else {
                                  interposed = .failed
                              }
                              interposeLock.unlock()
                          }
                      }
                  }
              }
              

              一些额外的context

              【讨论】:

                【解决方案18】:

                创建一个名为 HostingController.swift 的新 swift 文件,或者在现有的 swift 文件中添加这个类

                class HostingController: UIHostingController<ContentView> {
                    override var preferredStatusBarStyle: UIStatusBarStyle {
                        return .darkContent //or .lightContent
                
                    }
                }
                

                然后更改 SceneDelegate.swift 中的代码行

                window.rootViewController = UIHostingController(rootView: contentView)
                

                window.rootViewController = HostingController(rootView: contentView)
                

                【讨论】:

                • 这与一年前的答案有何不同?
                【解决方案19】:

                在所有提议的解决方案中,侵入性较小、最直接、实际上唯一对我们有用的是 Michał Ziobro 提出的解决方案: https://stackoverflow.com/a/60188583/944839

                在我们的应用程序中,我们需要将屏幕显示为带有深色状态栏的sheet。这两种简单的解决方案(比如设置preferredColorScheme)都没有为我们工作。但是,手动强制应用程序配色方案在显示为工作表的屏幕的onAppear 中并在onDisappear 中恢复它就可以了。

                这是完整的扩展代码:

                import SwiftUI
                import UIKit
                
                extension ColorScheme {
                    var interfaceStyle: UIUserInterfaceStyle {
                        switch self {
                        case .dark: return .dark
                        case .light: return .light
                        @unknown default: return .light
                        }
                    }
                }
                
                extension SceneDelegate {
                    static var current: Self? {
                        let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
                        return windowScene?.delegate as? Self
                    }
                }
                
                extension UIApplication {
                    static func setColorScheme(_ colorScheme: ColorScheme) {
                        if let window = SceneDelegate.current?.window {
                            window.overrideUserInterfaceStyle = colorScheme.interfaceStyle
                            window.setNeedsDisplay()
                        }
                    }
                }
                

                P.S.为了让屏幕本身仍然使用light 配色方案,我们将colorScheme(.light) 修饰符应用于body 的内容。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2022-11-11
                  • 1970-01-01
                  • 2020-04-21
                  • 1970-01-01
                  • 2021-01-28
                  • 2015-11-20
                  • 2011-08-13
                  相关资源
                  最近更新 更多