也许我的方法能帮到你。在Xcode 15和iOS 17.1上测试过。ScrollView()没有被阻塞。
struct MultiTapButton<Label> : View where Label : View {
let label: Label
let singleTapAction: () -> Void
let doubleTapAction: () -> Void
let longPressAction: () -> Void
let duration: Double
init(singleTapAction: @escaping () -> Void, doubleTapAction: @escaping () -> Void, longPressAction: @escaping () -> Void, duration: Double, @ViewBuilder label: () -> Label) {
self.label = label()
self.singleTapAction = singleTapAction
self.doubleTapAction = doubleTapAction
self.longPressAction = longPressAction
self.duration = duration
}
@GestureState private var onPressing: Bool = false
@State var longAction: Bool = false
var gesture: some Gesture {
LongPressGesture(minimumDuration: duration)
.updating($onPressing) { currentState, gestureState, transaction in
gestureState = currentState
transaction.animation = Animation.spring(duration: 0.0625)
}
.onEnded { finished in
longAction = true
longPressAction()
}
}
var body: some View {
Button(action: {
if longAction {
longAction = false
return
}
singleTapAction()
}) {
label
}
.simultaneousGesture(gesture)
.highPriorityGesture(
TapGesture(count: 2)
.onEnded { _ in
doubleTapAction()
}
)
}
}
例子:
struct ExampleView: View {
let gridItems = [GridItem(.fixed(120), spacing: 2), GridItem(.fixed(120), spacing: 2), GridItem(.fixed(120), spacing: 2)]
var body: some View {
ZStack(){
Color.orange
ScrollView(showsIndicators: true){
LazyVGrid(columns: gridItems, alignment: .center, spacing: 2) {
ForEach(0..<24) { index in
MultiTapButton(singleTapAction: {
print("Single Tap Action")
}, doubleTapAction: {
print("Double Tap Action")
}, longPressAction: {
print("Long Press Action")
}, duration: 0.5) {
Rectangle()
.foregroundStyle(Color.purple)
.frame(width: 120, height: 150, alignment: .center)
}
}
}
.padding(.vertical, 64)
}
}
.ignoresSafeArea()
}
}