首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么在rootViewController生命周期中将UIHostingController设置为UIHostingController时会出现错误?

为什么在rootViewController生命周期中将UIHostingController设置为UIHostingController时会出现错误?
EN

Stack Overflow用户
提问于 2021-12-30 00:55:52
回答 1查看 146关注 0票数 -2

我试图在最新的SwiftUI生命周期中设置状态栏样式。下面是我的代码,它执行执行此操作的逻辑,改编自这里

代码语言:javascript
复制
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放在我的根应用程序中,如下所示:

代码语言:javascript
复制
@main
struct App: SwiftUI.App {
  var body: some Scene {
    WindowGroup {
      StatusBarControllerView {
        Text("Content goes here")
      }
    }
  }
}

虽然它的视觉效果很好,但我现在在控制台中得到了以下错误:

代码语言:javascript
复制
Unbalanced calls to begin/end appearance transitions for <_TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier__: 0x13ee0d9d0>.

有人知道如何修改所提供的代码以避免此错误消息吗?在private extension UIApplicationwindows.first?.rootViewController = hostingController中设置根视图控制器时会出现此问题。

澄清1/3/2021

我试图以这种方式而不是通过编辑plist来更改状态栏颜色的原因是,我希望能够在我的应用程序的任何视图中动态地更改状态栏颜色,而不是应用程序范围的颜色,如下所示:

代码语言:javascript
复制
struct MyView: View {
  var body: some View {
    MySubview()
      .statusBar(style: .darkContent)
  }
}
EN

回答 1

Stack Overflow用户

发布于 2022-01-03 19:33:46

在深入研究杂草之前,我看到了一些答案,让我相信这是不必要的,可以通过改变您的plist:这里这里来解决。

假设您确实想要一个主机控制器,我相信问题在于您正在以两种不同的方式设置视图。一个是从应用程序主体调用的空视图(通过StatusBarControllerView),另一个是通过窗口rootViewController分配控制的托管UIView。这可以通过使用一些可见视图更改EmptyView()来演示;它不会出现,因为HostingController正在替换它。Swift能够替换它,但是抛出你看到的错误,让你知道这正在发生。如果您确实希望HostingController成为主视图,可以通过将StatusBarControllerView更改为UIViewRepresentable来直接设置它:

代码语言:javascript
复制
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在场景委托中设置这个答案。然而,这将需要添加场景委托和应用程序委托到您的项目(这里有一个很好的教程)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70526459

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档