I attempted to apply a cornerRadius
to the NavigationStack
, but as a result, the touch area became restricted to the initial view position. In simpler terms, if the slider is closed, you cannot open it by tapping it unless you touch the red area depicted in the image. (ControllerView
is responsible for animation)
import SwiftUI
private struct ControllerView<Content: View>: View {
private var content: Content
@Binding var isOpen: Bool
init(isOpen: Binding<Bool>, @ViewBuilder content: () -> Content) {
self._isOpen = isOpen
self.content = content()
}
var body: some View {
GeometryReader { proxy in
ZStack {
Color.yellow.ignoresSafeArea()
content
.cornerRadius(30) /// <- Here
.offset(x: isOpen ? 300 : 0)
}
.ignoresSafeArea()
}
}
}
private struct GreenView: View {
@Binding var isOpen: Bool
@Binding var navigation : [AnyHashable]
var body: some View {
NavigationStack(path: $navigation) {
Color.green.ignoresSafeArea()
.onTapGesture {
print("GreenView tapped!")
withAnimation { isOpen.toggle() }
}
}
}
}
struct SwiftUIView9: View {
@State private var isOpen = true
var body: some View {
ControllerView(isOpen: $isOpen) {
GreenView(isOpen: $isOpen, navigation: .constant([]))
}
}
}
#Preview {
SwiftUIView9()
}
By trial and error, I found that if isOpen
is initially false
, i.e. initially offset(0)
, then the tap area is correct.
We can exploit this by setting the offset initially to 0, and then immediately to isOpen ? 300 : 0
when the view appears
@State var appeared = false
var correctOffset: CGFloat {
if !appeared {
return 0
}
return isOpen ? 300 : 0
}
Add an onAppear
to set appeared
to true:
content
.cornerRadius(30)
.offset(x: correctOffset)
.onAppear {
DispatchQueue.main.async {
appeared = true
}
}
This incorrect touch area behaviour is happening with some other modifiers too, clipped
, colorInvert
etc. This might just be another quirk with NavigationStack
.