我想要使用长按手势来检测用户何时连续按住1秒,我还想检测用户何时松开屏幕.目前,onChanged检测手势何时开始,onEnded在1秒后触发.因此,我可以使用onEnded来检测用户连续等待1秒的时间.但是我怎么知道用户什么时候放手呢?

Color.blue
                .simultaneousGesture(LongPressGesture(minimumDuration: 1.0)
                    .onChanged { _ in
                        UIImpactFeedbackGenerator(style: .light).impactOccurred()
                    }
                    .onEnded { _ in
                        UIImpactFeedbackGenerator(style: .light).impactOccurred()
                    }
                )

推荐答案

正如您已经发现的,LongPressGesture在触发它所需的时间间隔过go 时结束,而不是在用户竖起手指时结束.因此,它不适合于检测手指抬起.

我会用DragGesture来代替.它的onChanged在手势开始时被调用,而它的onEnded在手指抬起时被调用.我们可以在onChanged中记录开始时间,在onEnded中记录结束时间,从而记录用户已经按下了多长时间.

@State var touchDownTime: Date?
@State var impactTrigger = false

var body: some View {
    Color.yellow
        .simultaneousGesture(
            DragGesture(minimumDistance: 0)
                .onChanged({ value in
                    if touchDownTime == nil {
                        touchDownTime = value.time
                        impactTrigger.toggle()
                        print("Started")
                    }
                })
                .onEnded({ value in
                    if let touchDownTime,
                       value.time.timeIntervalSince(touchDownTime) >= 1 {
                        impactTrigger.toggle()
                        print("Ended")
                    }
                    self.touchDownTime = nil
                })
        )
        .sensoryFeedback(.impact(weight: .light), trigger: impactTrigger)
}

请注意,我已经将其更改为使用sensoryFeedback来创建触觉反馈.如果你的目标是比iOS 17更旧的版本,使用UIImpactFeedbackGenerator也可以.

请注意,与LongPressGesture不同的是,当用户按下手指后移动太多时不会触发,而如果手指移动,DragGesture仍然可以识别.如果这是不需要的,请使用value.translation属性来确定手指是否移动太多.

@State var shouldCancel = false
...
.onChanged({ value in
    ...
    let threshold: CGFloat = 10 // decide a threshold
    if hypot(value.translation.width, value.translation.height) > threshold {
        shouldCancel = true
    }
})
.onEnded({ value in
    if let touchDownTime,
       !shouldCancel, // <----
       value.time.timeIntervalSince(touchDownTime) >= 1 {
        impactTrigger.toggle()
        print("Ended")
    }
    self.touchDownTime = nil
    shouldCancel = false
})

Ios相关问答推荐

自定义alert 未执行任何操作

如何加密字符串使用AES. GCM在Dart和解密相同的Swift?

如何在SwiftUI中扩展 colored颜色 超出顶部边缘

withTaskGroup不适用于CLGeocoder

当操作修改查看条件时,按钮不重复

如何在后台显示 Swift UI 中的通讯通知?

如何在Swift中同时实现三个手势?

SwiftUI - 搜索栏和导航标题之间的空间太大

如何使用 Rxswift 处理程序最喜欢的按钮

拔下设备后,DriverKit USB 驱动程序 (dext) 进程不会终止

使用 SwiftUI 显示多个 VNRecognizedObjectObservation 边界框时偏移量错误

react 在 android 上运行的本机应用程序,但在 iOS 上出现问题,详细信息在描述中共享

如何仅更改一个视图的导航标题 colored颜色 ?

SwiftUI - 在ForEach的每个元素之间自动添加分隔符

检测 iPhone 应用程序中是否存在摄像头?

iOS 8 - 使用自定义演示关闭视图控制器后屏幕空白

获取 iOS 上所有联系人的列表

iPhone 未连接.连接 iPhone 后 Xcode 将继续

iOS UITextView 或 UILabel 带有可点击的动作链接

使用 Xcode 的 All Exceptions 断点时忽略某些异常