Nested Tabview - Remove Inner Tab Bar iOS 13, Swift Ui

Nested TabView - Remove inner tab bar iOS 13, Swift UI

Hide it explicitly... as it is for backward compatibility it is safe, because behavior is already known and won't change.

So here is a solution

var body: some View {
TabView(selection: $outerTabViewSelectedTab,
content: {
Text("Outer 1").tabItem { Text("Outer 1") }.tag(1)
TabView(selection: $innerTabViewSelectedTab,
content: {
Text("Inner 1").tag(1)
.background(TabBarAccessor { tabBar in
tabBar.isHidden = true
})
Text("Inner 2").tag(2)
}).tabItem { Text("Outer 2") }.tag(2)
})
}

Used TabBarAccessor from my other solution in https://stackoverflow.com/a/59972635/12299030

SwiftUI Hide TabView bar inside NavigationLink views

If we talk about standard TabView, the possible workaround solution can be based on TabBarAccessor from my answer on Programmatically detect Tab Bar or TabView height in SwiftUI

Here is a required modification in tab item holding NavigationView. Tested with Xcode 11.4 / iOS 13.4

demo

struct FirstTabView: View {
@State private var tabBar: UITabBar! = nil

var body: some View {
NavigationView {
NavigationLink(destination:
FirstChildView()
.onAppear { self.tabBar.isHidden = true } // !!
.onDisappear { self.tabBar.isHidden = false } // !!
) {
Text("Go to...")
}
.navigationBarTitle("FirstTitle", displayMode: .inline)
}
.background(TabBarAccessor { tabbar in // << here !!
self.tabBar = tabbar
})
}
}

Note: or course if FirstTabView should be reusable and can be instantiated standalone, then tabBar property inside should be made optional and handle ansbsent tabBar explicitly.

SwiftUI TabView inside a NavigationView

It is perfectly fine to have TabView() inside a NavigationView. Every time we switch between pages in any app, the navigating is mostly expected, so almost every view is inside the NavigtionView for this reason.

You can achieve this design with something like this (see the bottom images also):

struct LoginDemo: View {
@State var username = ""
var body: some View {
NavigationView {
VStack {
TextField("Enter your user name", text: $username)
.font(.headline)
.multilineTextAlignment(.center)
.frame(width: 300)
.border(.black)
NavigationLink {
GotoTabView()
} label: {
Text("search")
}
.disabled(username == "Admin" ? false : true)
}
}
.navigationTitle("Hey It's Nav View")
}
}
struct GotoTabView: View {
@State var temp = "status"
@State var selection = "view1"
var body: some View {
TabView(selection: $selection) {
Image("Swift")
.resizable()
.frame(width: 300, height: 300)
.tabItem {
Text("view 1")
}
.tag("view1")
Image("Swift")
.resizable()
.frame(width: 500, height: 500)
.tabItem {
Text("view 2")
}
.tag("view2")
}
.onChange(of: selection){ _ in
if selection == "view1" {
temp = "status"
}
else {
temp = "hero"
}
}
.toolbar{
ToolbarItem(placement: .principal) {
Text(temp)
}
}
}
}

NavigationView:

Sample Image

TabView:

Sample Image

Sample Image

SWIFTUI: Take out a gray rectangle on top of the TabBar

Remove the marked part of hack from TabBar view and that glitch will go.

Tested with Xcode 11.4 / iOS 13.4

demo

        }   .onAppear {
// UITabBar.appearance().isTranslucent = false // << this one !!
UITabBar.appearance().barTintColor = UIColor(named: "IkeaBlu")
}.accentColor(Color(.white))

How can I hide TabBar Swift UI?

Create CustumPresentViewController.swift -

    import UIKit
import SwiftUI

struct ViewControllerHolder {
weak var value: UIViewController?
}

struct ViewControllerKey: EnvironmentKey {
static var defaultValue: ViewControllerHolder { return
ViewControllerHolder(value:
UIApplication.shared.windows.first?.rootViewController ) }
}

extension EnvironmentValues {
var viewController: ViewControllerHolder {
get { return self[ViewControllerKey.self] }
set { self[ViewControllerKey.self] = newValue }
}
}

extension UIViewController {
func present<Content: View>(style: UIModalPresentationStyle =
.automatic, @ViewBuilder builder: () -> Content) {
// Must instantiate HostingController with some sort of view...
let toPresent = UIHostingController(rootView:
AnyView(EmptyView()))
toPresent.modalPresentationStyle = style
// ... but then we can reset rootView to include the environment
toPresent.rootView = AnyView(
builder()
.environment(\.viewController, ViewControllerHolder(value:
toPresent))
)
self.present(toPresent, animated: true, completion: nil)
}
}

Use this in required View -

@Environment(\.viewController) private var viewControllerHolder:  
ViewControllerHolder

private var viewController: UIViewController? {
self.viewControllerHolder.value
}

var body: some View {
NavigationView {
ZStack {
Text("Navigate")
}.onTapGesture {
self.viewController?.present(style: .fullScreen) {
EditUserView()
}
}
}
}

Programmatically detect Tab Bar or TabView height in SwiftUI

As bridge to UIKit is officially allowed and documented, it is possible to read needed information from there when needed.

Here is possible approach to read tab bar height directly from UITabBar

// Helper bridge to UIViewController to access enclosing UITabBarController
// and thus its UITabBar
struct TabBarAccessor: UIViewControllerRepresentable {
var callback: (UITabBar) -> Void
private let proxyController = ViewController()

func makeUIViewController(context: UIViewControllerRepresentableContext<TabBarAccessor>) ->
UIViewController {
proxyController.callback = callback
return proxyController
}

func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<TabBarAccessor>) {
}

typealias UIViewControllerType = UIViewController

private class ViewController: UIViewController {
var callback: (UITabBar) -> Void = { _ in }

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let tabBar = self.tabBarController {
self.callback(tabBar.tabBar)
}
}
}
}

// Demo SwiftUI view of usage
struct TestTabBar: View {
var body: some View {
TabView {
Text("First View")
.background(TabBarAccessor { tabBar in
print(">> TabBar height: \(tabBar.bounds.height)")
// !! use as needed, in calculations, @State, etc.
})
.tabItem { Image(systemName: "1.circle") }
.tag(0)
Text("Second View")
.tabItem { Image(systemName: "2.circle") }
.tag(1)
}
}
}

How to remove the default Navigation Bar space in SwiftUI NavigationView

For some reason, SwiftUI requires that you also set .navigationBarTitle for .navigationBarHidden to work properly.

NavigationView {
FileBrowserView(jsonFromCall: URLRetrieve(URLtoFetch: applicationDelegate.apiURL))
.navigationBarTitle("")
.navigationBarHidden(true)
}

Update

As @Peacemoon pointed out in the comments, the navigation bar remains hidden as you navigate deeper in the navigation stack, regardless of whether or not you set navigationBarHidden to false in subsequent views. As I said in the comments, this is either a result of poor implementation on Apple's part or just dreadful documentation (who knows, maybe there is a "correct" way to accomplish this).

Whatever the case, I came up with a workaround that seems to produce the original poster's desired results. I'm hesitant to recommend it because it seems unnecessarily hacky, but without any straightforward way of hiding and unhiding the navigation bar, this is the best I could do.

This example uses three views - View1 has a hidden navigation bar, and View2 and View3 both have visible navigation bars with titles.

struct View1: View {
@State var isNavigationBarHidden: Bool = true

var body: some View {
NavigationView {
ZStack {
Color.red
NavigationLink("View 2", destination: View2(isNavigationBarHidden: self.$isNavigationBarHidden))
}
.navigationBarTitle("Hidden Title")
.navigationBarHidden(self.isNavigationBarHidden)
.onAppear {
self.isNavigationBarHidden = true
}
}
}
}

struct View2: View {
@Binding var isNavigationBarHidden: Bool

var body: some View {
ZStack {
Color.green
NavigationLink("View 3", destination: View3())
}
.navigationBarTitle("Visible Title 1")
.onAppear {
self.isNavigationBarHidden = false
}
}
}

struct View3: View {
var body: some View {
Color.blue
.navigationBarTitle("Visible Title 2")
}
}

Setting navigationBarHidden to false on views deeper in the navigation stack doesn't seem to properly override the preference of the view that originally set navigationBarHidden to true, so the only workaround I could come up with was using a binding to change the preference of the original view when a new view is pushed onto the navigation stack.

Like I said, this is a hacky solution, but without an official solution from Apple, this is the best that I've been able to come up with.

NavigationView title doesn't appear when the views are in TabView in SwiftUI

The first thing to point out here is that all of the navigation bar modifiers you have in your code should be modifiers on a view inside of the NavigationView, not modifiers on NavigationView itself. From the documentation for .navigationBarTitle, for example:

This modifier only takes effect when this view is inside of and visible within a NavigationView.

Also, there is no need to have a NavigationView wrapping your TabView and then another inside your MainContentView. This will only lead to nested navigation bars, and you definitely don't want that. Instead, just use one NavigationView. I would also suggest that you not put the NavigationView inside the MainContentView body.

I've refactored your code to show what I'm talking about, although I wasn't sure where you were trying to use .navigationBarBackButtonHidden and .navigationBarHidden, so I omitted them. Just keep in mind that they function just like .navigationBarTitle - you need to use them as modifiers on a view inside NavigationView, not on NavigationView itself.

struct TabBarView: View {
var body: some View {
TabView {
NavigationView {
MainContentView()
}
.tag(0)
.tabItem {
Text("Main")
}

SearchContentView()
.tag(1)
.tabItem {
Text("Search")
}
}
}
}
struct MainContentView: View {
var body: some View {
Text("Some Content View")
.navigationBarTitle("Travel")
}
}

As you might notice, I also removed the VStack from .tabItem. You can put both Text and Image inside .tabItem without the need for a VStack, and if I'm not mistaken, .tabItem ignores anything that is not Text or Image anyway.



Related Topics



Leave a reply



Submit