You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI视图嵌入UIHostingController后配色方案切换失效

解决SwiftUI嵌入UIHostingController后配色方案切换失效问题

问题根源:将SwiftUI视图嵌入UIHostingController时,UIKit的overrideUserInterfaceStyle设置优先级高于SwiftUI的preferredColorScheme,导致SwiftUI内部的配色切换无法同步到整个嵌入视图。

方案一:状态提升至UIKit层,双向绑定同步

步骤1:修改SwiftUI视图,使用@Binding传递状态

将原视图中的@State private var isDarkMode改为@Binding,让UIKit层可以共享并监听这个状态:

struct SettingsSUView: View {
  @State private var isPresented = false
  @Binding var isDarkMode: Bool // 改为Binding类型
  var body: some View {
    Button("Show Sheet") {
      isPresented = true
    }
    .sheet(isPresented: $isPresented) {
      List {
        Toggle("Dark Mode", isOn: $isDarkMode)
      }
      .preferredColorScheme(isDarkMode ? .dark : .light)
    }
  }
}

#Preview {
  SettingsSUView(isDarkMode: .constant(true))
}

步骤2:在UIKit控制器中管理状态并同步配色

在嵌入SwiftUI的UIViewController中,创建状态变量并绑定到SwiftUI视图,同时通过didSet监听状态变化,更新UIHostingController的overrideUserInterfaceStyle:

class YourParentVC: UIViewController {
  private var isDarkMode = true {
    didSet {
      // 状态变化时同步更新UIHostingController的配色
      contentHostingController.overrideUserInterfaceStyle = isDarkMode ? .dark : .light
    }
  }
  private lateinit var contentHostingController: UIHostingController<SettingsSUView>

  override func viewDidLoad() {
    super.viewDidLoad()
    setupHostingController()
  }

  private func setupHostingController() {
    // 将UIKit的状态绑定到SwiftUI视图
    let rootView = SettingsSUView(isDarkMode: $isDarkMode)
    contentHostingController = UIHostingController(rootView: rootView)
    // 初始化配色
    contentHostingController.overrideUserInterfaceStyle = isDarkMode ? .dark : .light
    
    addChild(contentHostingController)
    view.addSubview(contentHostingController.view)
    
    contentHostingController.view.snp.makeConstraints { make in
      make.edges.equalToSuperview()
    }
    
    contentHostingController.didMove(toParent: self)
  }
}

方案二:通过环境传递UIHostingController引用同步

如果不想将状态提升到UIKit层,可以通过自定义环境键传递UIHostingController的引用,在SwiftUI内部直接更新其配色设置。

步骤1:定义自定义环境键

struct HostingControllerKey: EnvironmentKey {
  static let defaultValue: UIHostingController<AnyView>? = nil
}

extension EnvironmentValues {
  var hostingController: UIHostingController<AnyView>? {
    get { self[HostingControllerKey.self] }
    set { self[HostingControllerKey.self] = newValue }
  }
}

步骤2:在UIKit中注入环境变量

创建UIHostingController时,将自身引用注入SwiftUI环境:

class YourParentVC: UIViewController {
  private lateinit var contentHostingController: UIHostingController<AnyView>

  override func viewDidLoad() {
    super.viewDidLoad()
    setupHostingController()
  }

  private func setupHostingController() {
    let rootView = SettingsSUView()
      .environment(\.hostingController, contentHostingController)
    
    contentHostingController = UIHostingController(rootView: rootView)
    addChild(contentHostingController)
    view.addSubview(contentHostingController.view)
    
    contentHostingController.view.snp.makeConstraints { make in
      make.edges.equalToSuperview()
    }
    
    contentHostingController.didMove(toParent: self)
  }
}

步骤3:在SwiftUI视图中监听状态变化更新配色

利用环境中的UIHostingController引用,在Toggle状态变化时同步更新其overrideUserInterfaceStyle:

struct SettingsSUView: View {
  @State private var isPresented = false
  @State private var isDarkMode = true
  @Environment(\.hostingController) private var hostingController
  
  var body: some View {
    Button("Show Sheet") {
      isPresented = true
    }
    .sheet(isPresented: $isPresented) {
      List {
        Toggle("Dark Mode", isOn: $isDarkMode)
          .onChange(of: isDarkMode) { newValue in
            hostingController?.overrideUserInterfaceStyle = newValue ? .dark : .light
          }
      }
      .preferredColorScheme(isDarkMode ? .dark : .light)
    }
    .onAppear {
      // 初始化时设置配色
      hostingController?.overrideUserInterfaceStyle = isDarkMode ? .dark : .light
    }
  }
}

内容的提问来源于stack exchange,提问作者Do Huynh Tuan Khai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 19:53:18