SwiftUI中UIHostingController内DismissAction无法生效问题排查
问题原因及解决方案
问题根源
你遇到的问题是因为SwiftUI的@Environment(\.dismiss)默认只适配SwiftUI自身的展示机制(比如sheet、fullScreenCover,或是NavigationStack的页面跳转),而你当前是通过UIKit的present(_:animated:completion:)方法展示包裹着UIHostingController的UINavigationController,这种情况下SwiftUI的dismiss环境变量无法关联到UIKit的控制器dismissal逻辑,所以调用dismiss()没有任何反应。
解决方案一:手动注入DismissAction
在创建UIHostingController时,手动给SwiftUI视图注入指向UIKit dismiss操作的DismissAction,这样点击Done按钮就能触发UIKit的控制器关闭逻辑。修改你的ViewController代码如下:
class ViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let testView = TestView() let hostingController = UIHostingController(rootView: testView) let navController = UINavigationController(rootViewController: hostingController) // 手动注入关联UIKit dismiss的DismissAction hostingController.rootView.environment(\.dismiss, DismissAction { navController.dismiss(animated: true) }) self.present(navController, animated: true) } }
解决方案二:改用SwiftUI的Sheet展示(推荐场景适配时使用)
如果你的业务场景允许,改用SwiftUI原生的sheet机制来展示TestView,此时@Environment(\.dismiss)会自动生效,无需额外配置。示例代码如下:
首先修改ViewController,嵌入一个负责触发展示的SwiftUI视图:
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let presentingView = UIHostingController(rootView: PresentingView()) addChild(presentingView) presentingView.view.frame = view.bounds view.addSubview(presentingView.view) presentingView.didMove(toParent: self) } } // 负责触发弹窗的SwiftUI视图 struct PresentingView: View { @State private var isTestViewPresented = false var body: some View { Button("打开测试视图") { isTestViewPresented = true } .sheet(isPresented: $isTestViewPresented) { TestView() .navigationBarTitleDisplayMode(.inline) } } }
你的TestView代码无需改动,点击Done按钮时dismiss()会自动关闭sheet。
内容的提问来源于stack exchange,提问作者Bill
相关产品推荐
相关产品推荐

