Swift UI检测手势的开始和结束

gtlvzcf8  于 5个月前  发布在  Swift
关注(0)|答案(1)|浏览(46)

我想使用长按手势并检测用户何时连续按住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()
                    }
                )

字符串

9gm1akwq

9gm1akwq1#

正如你所发现的,LongPressGesture在触发它所需的时间间隔结束时,而不是在用户抬起手指时结束。因此,它不适合检测手指抬起。
我会使用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,如果手指移动,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
})

相关问题