如何在嵌套UIHostingController的UITabBarController实现全屏覆盖加载视图
问题描述
我有一个包含2个项目的UITabBarController,第一个视图控制器是嵌套了承载SwiftUI HomeView的UIHostingController的UINavigationController,HomeView可通过NavigationLink跳转到SecondView。现在需要从SecondView触发一个全屏覆盖的加载视图,要求覆盖整个界面(包括TabBar),且方案需支持iOS 13及以上,求最佳实现方式。
相关代码
App启动配置代码
tabBarCnt.tabBar.tintColor = UIColor.black let firstVc = UINavigationController(rootViewController: UIHostingController(rootView: HomeView())) firstVc.title = "First" let secondVc = UIViewController() secondVc.title = "Second" tabBarCnt.setViewControllers([firstVc, secondVc], animated: false) UIApplication.shared.windows.first?.rootViewController = tabBarCnt UIApplication.shared.windows.first?.makeKeyAndVisible()
HomeView代码
struct HomeView: View { var body: some View { NavigationView { VStack{ Text("Home View") NavigationLink { SecondView() } label: { Text("Press here to go to second page") } } } .navigationBarTitle("NAVIGATION TITLE") } }
SecondView代码
struct SecondView: View { var body: some View { VStack(spacing: 20) { Text("Second View") Text("How can I make a modal view that covers the entire view and the tabBar ??? the View should get triggered from there. BAsically I want to make a loading view that covers everything.") } } }
解决方案
方案一:SwiftUI全屏模态+UIKit样式配置(兼容iOS13+)
利用SwiftUI的fullScreenCover组件,手动配置UIKit模态样式确保覆盖TabBar:
- 先定义加载视图:
struct LoadingView: View { var body: some View { ZStack { Color.black.opacity(0.7) .ignoresSafeArea() VStack { ProgressView() .scaleEffect(1.5) .tint(.white) Text("加载中...") .foregroundColor(.white) .padding(.top, 16) } } } }
- 修改
SecondView添加触发逻辑:
struct SecondView: View { @State private var isLoading = false var body: some View { VStack(spacing: 20) { Text("Second View") Button("触发全屏加载") { isLoading = true // 模拟加载过程,3秒后关闭 DispatchQueue.main.asyncAfter(deadline: .now() + 3) { isLoading = false } } } .fullScreenCover(isPresented: $isLoading) { LoadingView() } .onAppear { // 强制设置全屏模态样式,确保覆盖TabBar if let hostingVc = UIApplication.shared.windows.first?.rootViewController?.presentedViewController as? UIHostingController<LoadingView> { hostingVc.modalPresentationStyle = .fullScreen } } } }
方案二:直接向App主窗口添加加载视图(最彻底)
完全脱离控制器层级,直接将加载视图挂载到应用主窗口,确保覆盖所有界面元素:
- 创建UIKit加载容器控制器:
class LoadingOverlayViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.black.withAlphaComponent(0.7) // 嵌入SwiftUI加载视图 let hostingVc = UIHostingController(rootView: LoadingView()) addChild(hostingVc) hostingVc.view.frame = view.bounds view.addSubview(hostingVc.view) hostingVc.didMove(toParent: self) } // 显示加载视图 func show() { guard let window = UIApplication.shared.windows.first else { return } window.addSubview(view) view.frame = window.bounds } // 隐藏加载视图 func hide() { view.removeFromSuperview() } }
- 在
SecondView中调用:
struct SecondView: View { let loadingOverlay = LoadingOverlayViewController() var body: some View { VStack(spacing: 20) { Text("Second View") Button("触发全屏加载") { loadingOverlay.show() DispatchQueue.main.asyncAfter(deadline: .now() + 3) { loadingOverlay.hide() } } } } }
方案三:环境变量传递顶层控制器(解耦设计)
通过SwiftUI环境对象注入顶层UITabBarController,从顶层控制器弹出全屏模态:
- 定义环境对象并在启动时注入:
// 定义共享状态对象 class AppState: ObservableObject { let rootTabBarController: UITabBarController init(tabBar: UITabBarController) { self.rootTabBarController = tabBar } } // 修改App启动代码 let tabBarCnt = UITabBarController() // ... 原有配置代码 ... // 创建环境对象并注入HomeView let appState = AppState(tabBar: tabBarCnt) let firstVc = UINavigationController(rootViewController: UIHostingController(rootView: HomeView().environmentObject(appState)))
- 在
SecondView中使用环境对象:
struct SecondView: View { @EnvironmentObject var appState: AppState var body: some View { VStack(spacing: 20) { Text("Second View") Button("触发全屏加载") { let loadingVc = UIHostingController(rootView: LoadingView()) loadingVc.modalPresentationStyle = .fullScreen // 从顶层TabBarController弹出模态 appState.rootTabBarController.present(loadingVc, animated: true) DispatchQueue.main.asyncAfter(deadline: .now() + 3) { loadingVc.dismiss(animated: true) } } } } }
内容的提问来源于stack exchange,提问作者P S
相关产品推荐
相关产品推荐

