Hot to set additional safe area insets in SwiftUI

1k views Asked by At

I'm trying to add additional padding to safe area dynamically. To achieve this I wrote modifier that wraps SwiftUI view into UIHostingController and sets additionalSafeAreaInsets on them:

extension View {
    func extendSafeArea() -> some View {
        modifier(ExtendedSafeAreaModifier())
    }
}

struct ExtendedSafeAreaModifier: ViewModifier {

    func body(content: Content) -> some View {
        Container(content: content)
            .edgesIgnoringSafeArea(.all)
    }

    private struct Container: UIViewRepresentable {
        let content: Content

        typealias UIViewType = UIView

        func makeUIView(context: Context) -> UIViewType {
            let hostingController = UIHostingController(rootView: content)
            hostingController.additionalSafeAreaInsets = .init(top: 0, left: 0, bottom: 200, right: 0)
            context.coordinator.container = hostingController
            return hostingController.view
        }

        func updateUIView(_ uiView: UIViewType, context: Context) {
            uiView.setNeedsLayout()
        }

        func makeCoordinator() -> Coordinator {
            .init()
        }

        class Coordinator {
            var container: UIViewController!
        }
    }
}

This works pretty well until it's being involved in complicated navigation:

struct ContentView: View {
    @State var tab: Int = 0
    
    var body: some View {
        TabView(selection: $tab) {
            NavigationView {
                ZStack {
                    Rectangle()
                        .foregroundColor(.red)
                    NavigationLink(
                        "B",
                        destination: Rectangle()
                            .foregroundColor(.blue)
                            .navigationBarTitle("B", displayMode: .inline)
                            .navigationBarHidden(false)
                    )
                }
                .navigationBarHidden(true)
                .navigationBarTitle("", displayMode: .inline)
            }
            .extendSafeArea()
            .tag(0)
            .tabItem {
                Text("A")
            }
            
            Text("C")
            .tag(1)
            .tabItem {
                Text("C")
            }
        }
    }
}

In the example above changing tabs makes NavigationView completely broken: Broken navigation

Can this behaviour be worked around? Is there another approach to achieve extending safe area? Thanks.

0

There are 0 answers