SwiftUI 使用 onTapGesture 和 onLongPressGesture 处理按钮/视图以及释放操作

我有一个同时具有 onTapGesture 和 onLongPressGesture 的视图。问题是我的 onLongPressGesture 的实现阻止了 onTapGesture 被调用。

这是一些代码

View()
      .onTapGesture {
           action_1
       }
      .onLongPressGesture(minimumDuration: 0.5, maximumDistance: 10, pressing: {
                                    pressing in
                                    self.isPressing = pressing
                                    if (pressing) {action_2}
                                    if !pressing {action_3}
                                }, perform: {})

.onLongPressGesture 中的 press 参数检测用户是否正在按下视图/按钮,并且将始终执行 .onLongPressGesture,无论 minimumDuration 是多少。

stack overflow SwiftUI handling button/view with onTapGesture and onLongPressGesture with a release action
原文答案
author avatar

接受的答案

### 编辑

Snapchat 快门,您可以在这里点击拍照,按住按钮开始录制视频,然后释放按钮停止录制视频。这就是为什么需要执行三个操作的原因。

这很棘手。这是我所做的:

  1. onTapGesture ,用于点击手势
  2. LongPressGesture ,延迟 0.5 秒。 0.5 秒结束后 ( .onEnded ),开始录制。
  3. DragGesture ,用于观察手指离开屏幕的时间。发生这种情况时,请停止录制。

    
    struct ContentView: View {
    
    /// for visual indicators
    @State var recording = false
    @State var tapped = false
    
    var body: some View {
        let longPressDrag = LongPressGesture(minimumDuration: 0.5) /// 2.
            .onEnded { _ in /// 0.5 seconds is over, start recording
                print("Long press start")
                recording = true
            }
            .sequenced(before: DragGesture(minimumDistance: 0)) /// 3.
            .onEnded { _ in /// finger lifted, stop recording
                print("Long press release")
                recording = false
            }
    
        Circle()
            .fill(recording ? Color.red : Color.blue)
            .opacity(tapped ? 0.5 : 1)
            .frame(width: 100, height: 100)
    
            .onTapGesture { /// 1.
                print("Tapped")
    
                tapped = true
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { tapped = false }
            }
            .gesture(longPressDrag)
    
    }
    }

结果:

 ![Snapchat-style button](https://i.stack.imgur.com/hC3uf.gif) 

* * *

**旧答案:**  `pressing`  参数不用于执行像  `action_2`  这样的操作。可以,但它更常用于更改  `@State` ,例如在按下时以绿色突出显示视图。您可以在  [community documentation](https://swiftontap.com/view/onlongpressgesture(minimumduration:maximumdistance:pressing:perform:) ) 中找到更多信息。

相反,您可能想要的是在  `action_2`  闭包中调用您的操作 ( `print("long")` / `perform` )。

struct ContentView: View {
var body: some View {
Text("Hi")
.font(.title)
.onTapGesture {
print("tap")
}
.onLongPressGesture(minimumDuration: 0.5, maximumDistance: 10) {
print("long")
}
}
}



结果:

 ![Both tap and long press work](https://i.stack.imgur.com/eCCup.gif) 

答案:

作者头像

XCode 14.Swift 5 我已将这两个手势添加到图像视图中。点击手势图像将缩放和取消缩放。在 LongPressGesture 上图像背景颜色会改变。提供 count: 2 使其成为 doubleTapGesture。

struct ContentView: View {
// MARK: - Property

@State private var isAnimating: Bool = false
@State private var imageScale: CGFloat = 1
@State private var shadowColor: Color = .black

// MARK: - Content
var body: some View {
    NavigationView {
        ZStack {
            Image("magazine-front-cover")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .cornerRadius(8)
                .padding()
                .shadow(color: shadowColor, radius: 22, x: 2, y: 2)
                .opacity(isAnimating ? 1 : 0)
                .animation(.linear(duration: 1), value: isAnimating)
                .scaleEffect(imageScale)
            // MARK: - 1. Tap Gesture
                .onTapGesture(count: 1, perform: {
                    if imageScale == 1 {
                        withAnimation(.spring()) {
                            imageScale = 5
                        }
                    } else {
                        withAnimation(.spring()) {
                            imageScale = 1
                        }
                    }
                })
            // MARK: - 2. LongPress Gesture
                .onLongPressGesture(perform: {
                    if shadowColor == .black {
                        shadowColor = .green
                    } else {
                        shadowColor = .black
                    }
                })
        }
        .ignoresSafeArea(edges: .all)
        .navigationTitle("Pinch & Zoom")
        .navigationBarTitleDisplayMode(.inline)
        .onAppear {
                isAnimating = true
        }
    } // END of Navigation View
  }
}

enter image description here