I am switching some screens of my app to use SwiftUI and now i have the structure as follows:
window?.rootViewController
is a UITabBarController
containing 1 UIViewController
and 2 UIHostingController
s (to be able to present SwiftUI views)
When i'm trying to present a SwiftUI view over another contained in UITabBarController it doesn't cover the UITabBar.
While I know how to get expected behavior in UIKit i am completely new to SwiftUI and can't solve this problem.
The structure and code i use are as follows:
AppDelegate
func presentInitialVC() {
if settings.firstLoad {
showOnboarding()
} else {
let tabBar = initTabBar()
window?.rootViewController = tabBar
}
}
private func initTabBar() -> UITabBarController {
let chatsViewController = {
let tabBarItem = UITabBarItem(title: "Explore", image: R.image.tabChats(), tag: 0)
tabBarItem.selectedImage = R.image.tabChatsSelected()
let view = ChatsView() // SwiftUI view
let hostingVC = UIHostingController(rootView: view)
hostingVC.tabBarItem = tabBarItem
return hostingVC
}()
let hubViewController = {
let tabBarItem = UITabBarItem(title: "Hub", image: R.image.tabHub(), tag: 1)
let view = HubMainView() // SwiftUI view
let vc = UIHostingController(rootView: view)
vc.tabBarItem = tabBarItem
return vc
}()
let settingsViewController = {
let tabBarItem = UITabBarItem(title: "Settings", image: R.image.tabSettings(), tag: 2)
tabBarItem.selectedImage = R.image.tabSettingsSelected()
let vc = SettingsViewController()
let navigationVC = UINavigationController(rootViewController: vc)
navigationVC.tabBarItem = tabBarItem
return navigationVC
}()
let tabBarController = UITabBarController(nibName: nil, bundle: nil)
tabBarController.tabBar.tintColor = R.color.buttonsColor()
tabBarController.viewControllers = [chatsViewController, hubViewController, settingsViewController]
return tabBarController
}
HubMainView + SharingRulesView
struct HubMainView: View {
@StateObject var viewModel = HubMainViewModel()
@State private var showSharingRules = false
var body: some View {
SharingRulesView(isPresented: showsSharingRules, onOkTapped: { showsSharingRules = false }) {
ZStack {
NavigationView {
ScrollView {
LazyVStack(spacing: 36) {
ForEach(mockedSections) { sectionViewModel in
HubSectionView(viewModel: sectionViewModel)
}
}
.padding(24)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Text("Hub")
.font(.system(size: 34, weight: .heavy))
.padding(.leading, 7)
}
}
}
.background(Color.secondaryBg)
}
}
}
}
}
// Container to add blur to the HubMainView and show some content
struct SharingRulesView<Content: View>: View {
var isPresented: Bool
@State var onOkTapped: VoidClosure
var content: () -> Content
var body: some View {
if !isPresented {
content()
} else {
ZStack(alignment: .center) {
content()
.blur(radius: 3)
Rectangle()
.fill(Color.black)
.opacity(0.4)
.edgesIgnoringSafeArea(.all)
CustomButton(onTapped: onOkTapped, title: "Ok")
.frame(width: 100, height: 59)
}
}
}
}
The only solution on my mind is to rewrite UITabBarController to SwiftUI view and present it from there. Are there any other solutions?
The thing is that in order to show SharingRulesView
it should be presented modally as a view controller over full screen not as a subview of HubMainView
. Hosting view controller of HubMainView
is in hierarchy of UITabViewController
, so if you show something inside of HubMainView
it will always be under tab bar.