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.