Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.7k views
in Technique[技术] by (71.8m points)

swift - NavigationView embedded in a UIHostingController has additional safe area insets

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...