在UIViewRepresentable中嵌入SwiftUI View:应在何处构建及刷新视图?
在UIViewRepresentable中嵌入SwiftUI View:应在何处构建及刷新视图?
我之前做混合开发的时候也纠结过这个问题,后来摸清楚了——核心就是靠UIHostingController这个“桥梁”,它能把SwiftUI View完美包装成UIKit能识别的控制器视图。下面给你说说具体的构建和刷新时机:
一、视图构建:放在makeUIView(context:)里
这个方法是UIViewRepresentable用来初始化UIKit视图的地方,只会调用一次,刚好适合创建UIHostingController并完成布局:
struct HostingWrapperView: UIViewRepresentable { @ViewBuilder let swiftUIView: () -> some View func makeUIView(context: Context) -> UIView { // 创建宿主控制器,传入要嵌入的SwiftUI View let hostingController = UIHostingController(rootView: swiftUIView()) let containerView = UIView() // 把宿主视图添加到容器,设置自动布局占满整个容器 hostingController.view.translatesAutoresizingMaskIntoConstraints = false containerView.addSubview(hostingController.view) NSLayoutConstraint.activate([ hostingController.view.topAnchor.constraint(equalTo: containerView.topAnchor), hostingController.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), hostingController.view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), hostingController.view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor) ]) return containerView } }
二、视图刷新:放在updateUIView(_:context:)里
当外部的状态(比如绑定的@State、@Binding值变化,或者UIViewRepresentable的属性更新)时,SwiftUI会自动调用updateUIView,这时候我们只需要更新UIHostingController的rootView就行:
func updateUIView(_ uiView: UIView, context: Context) { // 从容器视图里找到对应的HostingController guard let hostingController = uiView.subviews.first?.next as? UIHostingController<some View> else { return } // 刷新根视图,触发SwiftUI View的更新 hostingController.rootView = swiftUIView() }
踩过的坑要提醒你
- 绝对别在
updateUIView里重新创建UIHostingController!每次创建都会销毁旧的控制器,不仅浪费性能,还可能导致视图状态丢失,比如输入框的内容、滚动位置这些。 - 要让SwiftUI能检测到状态变化,一定要把影响SwiftUI View的参数都作为
HostingWrapperView的属性——比如你要传个用户名进去,就定义let userName: String,这样当userName变了,updateUIView才会被调用。
内容来源于stack exchange
相关产品推荐
相关产品推荐

