NavigationView embedded in a UIHostingController has additional safe area insets
Asked Answered
T

4

6

Anyone know how to deal with this? Seems as though when you have a UIHostingController with a NavigationView the following happens:

enter image description here

Notice the big grey tab bar safe area.

This is primarily a UIKit application. Were replacing on of our tabs in the tab bar with A swiftUI view.

here is my code:

var body: some View {
    NavigationView {
        ZStack {
            MapKitMapView(
                mapView: mapView,
                annotations: $annotations,
                polylines: $polylines,
                centerCoordinate: $centerCoordinate,
                newMapRegion: $newMapRegion,
                userTrackingMode: $userTrackingMode
            )
            .edgesIgnoringSafeArea(.all)
            .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
            
            ButtonLayer(mapView: mapView, userTrackingMode: $userTrackingMode, showSheet: $showSheet)
                .frame(maxWidth: .infinity, maxHeight: .infinity)
                .padding(.margin)
        }
        .edgesIgnoringSafeArea(.all)
        .navigationBarHidden(true)
        .sheet(isPresented: $showSheet) {
            SettingsView()
        }
    }
}

pardon the censorship. I want the app to remain anonymous.

But essentially my UITabBar is built as follows:

  • there is a global UINavigationViewController
  • the first and only item in the UINavigationController is this UITabBar
  • The UITabBar tabs are all created programatically.
  • The tab in question is just a UIHostingController with the code you see above as the rootView.

I have tried manually setting additional safe area insets to the UIHostingController to make it expand outside of the safe area.

If I remove the NavigationView everything looks and functions as intended.

Tadashi answered 12/1, 2021 at 20:29 Comment(0)
T
9

I found a workaround for this issue. However, I would like to use a pure swiftUI solution rather than the below workaround. So I am leaving this open to see if someone else has some other insight.

Upon inspecting the view hierarchy debugger, I noticed the following:

The View is wrapped in a NotifyingMultiColumnSplitViewController

The navigation view style is SplitView... which is an iPad style. I am not actually setting my style. So maybe a bug is causing it to default to that.

I tried changing the NavigationView styling to StackNavigationViewStyle().

While this didn't fix the problem, It did cleanup the view hierarchy and wrap my UIHostingViewController in a proper UINavigationController.

It also changed the bottom grey "safe area" to white.

What this tells me, is that NavigationView just wraps your view in a standard UINavigationController when its being used in a UIHostingController. And since im interfacing with UIKit, maybe it makes more sense to set the root of my tab bar to a UINavigationController rather than a UIHostingController with a NavigationView inside of it.

So the tab that was experiencing the issue is now being populated with:

UINavigationController(rootViewController: UIHostingController(rootView: MyView()))

and my view code is just:

ZStack {
        MapKitMapView(
            mapView: mapView,
            annotations: $annotations,
            polylines: $polylines,
            centerCoordinate: $centerCoordinate,
            newMapRegion: $newMapRegion,
            userTrackingMode: $userTrackingMode
        )
        .edgesIgnoringSafeArea(.all)
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
        
        ButtonLayer(mapView: mapView, userTrackingMode: $userTrackingMode, showSheet: $showSheet)
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .padding(.margin)
    }
    .edgesIgnoringSafeArea(.all)
    .navigationBarHidden(true)
    .sheet(isPresented: $showSheet) {
        SettingsView()
    }

This actually corrected the issue. And I am able to push views without any problems using NavigationLinks.

I guess the lesson to learn here is:

SwiftUI interfaces with UIKit better than I thought.

What I still don't know is: Why was NavigationView having this problem if it just wraps your view in a UINavigationController? I tried reproducing it in a clean project and had no luck. So I suspect something being done in our app to customize the navigation bar or tab bar is causing this issue.

After much digging I could not find a root cause. So this workaround will have to suffice for the time being.

Tadashi answered 12/1, 2021 at 22:16 Comment(1)
Thanks for writing this up. I was having a very similar problem and setting StackNavigationViewStyle() fixed my issue as well.Knotty
S
2

This situation happens when you embed UIHostingController in UITabBar. To remove this gray line, just set the translucency of the UITabBar.

tabBar.isTranslucent = true
Statant answered 10/2, 2022 at 10:7 Comment(1)
Well sure, if you want a translucent tabBar, but what if you don't?Astigmatic
L
2

This is how I fixed a similar problem.

  1. Remove the NavigationView from the SwiftUI View.
  2. Set the title for the view controllers navigation bar.
     let vc = UIHostingController(rootView: MyView())
     vc.navigationItem.title = "Title"
     return UINavigationController(rootViewController: vc)
    
Larceny answered 28/9, 2022 at 13:58 Comment(0)
S
0
self.tabBarController?.tabBar.isTranslucent = true

Worked for me.

Sauna answered 21/12, 2022 at 12:15 Comment(1)
This does place the "grey" bar under the TabBar but what if you don't use/want a translucent tabBar?Astigmatic

© 2022 - 2024 — McMap. All rights reserved.