SwiftUI: Cancel TapGesture on parent view

半城伤御伤魂 提交于 2020-06-15 11:55:55

问题


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?


回答1:


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




回答2:


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)
    }
}


来源:https://stackoverflow.com/questions/59946147/swiftui-cancel-tapgesture-on-parent-view

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!