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
相关产品推荐
相关产品推荐

