I have view hierarchy in SwiftUI like
ParentView {
//other views
ChildView().highPriorityGesture(TapGesture().onEnded {
print("Tap!")
})
// other views
}self.gesture(tap)
And I want to have parent view handle all taps on the screen in spite of cases when user taps onto ChildView. Now both closures executes. How to stop tap gesture events propagating up view hierarchy?
Well, probably there is some specific in which exactly ChildView
and ParentView
, because as tested below (Xcode 11.2 / iOS 13.2) child view gesture just overrides parent view gesture.
Here is demo.. tapped in yellow area, then tapped in green area - no mix callbacks
Complete module code
import SwiftUI
struct TestGesturesPriority: View {
var body: some View {
VStack {
Text("Hello, World!")
.padding()
.background(Color.yellow)
.gesture(TapGesture().onEnded {
print(" -- child")
})
}
.frame(width: 400, height: 400)
.background(Color.green)
.gesture(TapGesture().onEnded {
print(">> parent")
})
}
}
Update: variant for List-Row
Yeees... List (Parent) - Row (Child) case appeared very challenging... please find below approach, it looks weird but tested & works
struct TestGesturesPriority: View {
let parentGesture = TapGesture().onEnded { // just for convenience
print(">> parent")
}
@GestureState private var captured = false
var body: some View {
List {
Text("Hello, World!").padding()
.background(Color.yellow)
.allowsHitTesting(true)
.gesture(DragGesture(minimumDistance: 0) // mimic Tap
.updating($captured, body: { (value, state, transaction) in
state = true // mark captured (will be reset automatically)
})
.onEnded { value in
// like Tap, but can be ignored if delta
// is large or out of view
print(" -- child")
}
)
}
.gesture(parentGesture, including: captured ? .subviews : .gesture)
}
}
To summarise - actually I think it is another List defect
backup
There's a slightly cleaner way to solve the tap localisation issue in List
as follows:
struct TestListGestures: View {
var body: some View {
List {
Text("Hello, World!").padding()
.background(Color.yellow)
.gesture(LongPressGesture(minimumDuration: 0.001) // resolve response time
.onEnded { value in
print(" -- child")
}
)
}
.gesture(LongPressGesture(minimumDuration: 0.001).onEnded({ _ in
print(" -- parent")
}), including: .gesture)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With