我试图在最新的SwiftUI生命周期中设置状态栏样式。下面是我的代码,它执行执行此操作的逻辑,改编自这里。
private class HostingController<Content: View>: UIHostingController<Content> {
override var preferredStatusBarStyle: UIStatusBarStyle {
return UIApplication.statusBarStyleHierarchy.last ?? UIApplication.defaultStatusBarStyle
}
}
/// By wrapping views in a StatusBarControllerView, they will become the app's main / primary view.
/// This will enable setting the statusBarStyle.
struct StatusBarControllerView<Content: View>: View {
var content: Content
init(@ViewBuilder content: () -> (Content)) {
self.content = content()
}
var body:some View {
EmptyView()
.onAppear {
UIApplication.shared.setHostingController(rootView: AnyView(content))
}
}
}
extension View {
/// Sets the status bar style color for this view.
func statusBar(style: UIStatusBarStyle) -> some View {
UIApplication.statusBarStyleHierarchy.append(style)
return self
// Once this view appears, set the style to the new style.
.onAppear {
UIApplication.hostingController?.setNeedsStatusBarAppearanceUpdate()
}
// Once it disappears, set it to the previous style.
.onDisappear {
UIApplication.statusBarStyleHierarchy.removeLast()
UIApplication.hostingController?.setNeedsStatusBarAppearanceUpdate()
}
}
}
private extension UIApplication {
static var hostingController: HostingController<AnyView>?
static var statusBarStyleHierarchy: [UIStatusBarStyle] = []
static let defaultStatusBarStyle: UIStatusBarStyle = .lightContent
/// Sets the App to start at rootView
func setHostingController(rootView: AnyView) {
let hostingController = HostingController(rootView: AnyView(rootView))
windows.first?.rootViewController = hostingController
UIApplication.hostingController = hostingController
}
}然后,我将StatusBarControllerView放在我的根应用程序中,如下所示:
@main
struct App: SwiftUI.App {
var body: some Scene {
WindowGroup {
StatusBarControllerView {
Text("Content goes here")
}
}
}
}虽然它的视觉效果很好,但我现在在控制台中得到了以下错误:
Unbalanced calls to begin/end appearance transitions for <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x13ee0d9d0>.有人知道如何修改所提供的代码以避免此错误消息吗?在private extension UIApplication:windows.first?.rootViewController = hostingController中设置根视图控制器时会出现此问题。
澄清1/3/2021
我试图以这种方式而不是通过编辑plist来更改状态栏颜色的原因是,我希望能够在我的应用程序的任何视图中动态地更改状态栏颜色,而不是应用程序范围的颜色,如下所示:
struct MyView: View {
var body: some View {
MySubview()
.statusBar(style: .darkContent)
}
}发布于 2022-01-03 19:33:46
在深入研究杂草之前,我看到了一些答案,让我相信这是不必要的,可以通过改变您的plist:这里和这里来解决。
假设您确实想要一个主机控制器,我相信问题在于您正在以两种不同的方式设置视图。一个是从应用程序主体调用的空视图(通过StatusBarControllerView),另一个是通过窗口rootViewController分配控制的托管UIView。这可以通过使用一些可见视图更改EmptyView()来演示;它不会出现,因为HostingController正在替换它。Swift能够替换它,但是抛出你看到的错误,让你知道这正在发生。如果您确实希望HostingController成为主视图,可以通过将StatusBarControllerView更改为UIViewRepresentable来直接设置它:
struct StatusBarControllerView<Content: View>: UIViewRepresentable {
var content: () -> (Content)
func makeUIView(context: Context) -> some UIView {
UIApplication.shared.setHostingController(rootView: AnyView(content()))
return UIApplication.hostingController?.view ?? UIView()
}
func updateUIView(_ uiView: UIViewType, context: Context) {}
}并删除行windows.first?.rootViewController = hostingController,使其只设置一次。
您还可以基于HostingController在场景委托中设置这个答案。然而,这将需要添加场景委托和应用程序委托到您的项目(这里有一个很好的教程)。
https://stackoverflow.com/questions/70526459
复制相似问题