There have been several questions like this one. There is a small difference which I didn’t notice in any other answers. Basically I have a TabView
and EACH of its items is wrapped inside NavigationView
. Because it is done this way and not the other way around first NavigationView
and than TabView
the way to hide the view is not that simple.
extension UIView {
func allSubviews() -> [UIView] {
var allSubviews = subviews
for subview in subviews {
allSubviews.append(contentsOf: subview.allSubviews())
}
return allSubviews
}
}
extension UITabBar {
private static var originalY: Double?
static public func changeTabBarState(shouldHide: Bool) {
let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
windowScene?.windows.first(where: { $0.isKeyWindow })?.allSubviews().forEach({ view in
if let tabBar = view as? UITabBar {
if !tabBar.isHidden && shouldHide {
originalY = tabBar.frame.origin.y
tabBar.frame.origin.y = UIScreen.main.bounds.height + 200
} else if tabBar.isHidden && !shouldHide {
guard let originalY else {
return
}
tabBar.frame.origin.y = originalY
}
tabBar.isHidden = shouldHide
}
})
}
}
struct MyTabView: View {
@Environment(.colorScheme) var colorScheme
@State var toggle = false
var body: some View {
TabView {
NavigationView {
ContentView(toggle: $toggle)
}
.tabItem {
Text("Profile")
.foregroundColor(colorScheme == .dark ? .white : .black)
}
}
.accentColor(colorScheme == .dark ? .white : .black)
.navigationBarTitleDisplayMode(.inline)
}
}
struct ContentView: View {
@Binding var toggle: Bool
var body: some View {
NavigationLink(isActive: $toggle, destination: {
Button("dismiss") {
UITabBar.changeTabBarState(shouldHide: false)
toggle.toggle()
}
.navigationBarBackButtonHidden()
.navigationBarHidden(true)
.onAppear {
UITabBar.changeTabBarState(shouldHide: true)
}
}, label: {
Text("Click")
})
}
}
@main
struct AppTestingOne: App {
var body: some Scene {
WindowGroup {
MyTabView()
}
}
}
The problem I get when doing this is the following. When I click the button at first screen I get sent here:
On first look there doesn’t seem to be a problem. In fact the button dismiss has like an invisible padding from the bottom. The interesting part is that when I rotate to landscape back to fullscreen, this padding disappears.
When you look at these pictures there doesn’t seem to be a problem, but when you have something at the top and at the bottom it gets pushed up and fixed when you re-rotate it.
2
Answers
I found out a very cool solution. When I hide the tabBar I can push its superview down depending on the phone (formula needs to be calculated) and after rotation it continues to work just fine by ignoring by how much I have pushed it and going back to the way it should be which because I calculated it for iPhone 12,13,14 and it works just as fine.
If you’re building for iOS 16, you can simply use
Example: