计算DragGesture的速度

时间:2019-07-26 15:16:33

标签: ios swift swiftui

我想提取DragGesture的速度,将其用于弹簧动画的initialVelocity参数。我正在尝试创建一个可移动的卡片,该卡片具有类似于Apple Maps应用程序中那样的响应式弹簧动画。

我尝试通过将拖动平移的高度除以拖动手势经过的总时间来计算速度。

v_abs = abs(Double(drag.translation.height / CGFloat(drag.time.timeIntervalSinceNow)))

问题在于,当用户开始拖动时,他们可能会在轻拂和释放之前放慢拖动速度,这会导致速度很慢,因为经过了很长一段时间。如果可能的话,我只想使用拖动手势最后几毫秒中的数据来计算速度。

4 个答案:

答案 0 :(得分:1)

最后,我得到了这样的速度。 (我想知道为什么在打印值时无法访问DragGesture.value的速度)

struct ContentView: View {

    @State private var previousDragValue: DragGesture.Value?

    func calcDragVelocity(previousValue: DragGesture.Value, currentValue: DragGesture.Value) -> (Double, Double)? {
        let timeInterval = currentValue.time.timeIntervalSince(previousValue.time)

        let diffXInTimeInterval = Double(currentValue.translation.width - previousValue.translation.width)
        let diffYInTimeInterval = Double(currentValue.translation.height - previousValue.translation.height)

        let velocityX = diffXInTimeInterval / timeInterval
        let velocityY = diffYInTimeInterval / timeInterval
        return (velocityX, velocityY)
    }

    var body: some View {
        return
            VStack {
                …
            }
            .gesture(DragGesture().onChanged {value in
                if let previousValue = self.previousDragValue {
                    // calc velocity using currentValue and previousValue
                    print(self.calcDragVelocity(previousValue: previousValue, currentValue: value))
                }
                // save previous value
                self.previousDragValue = value
            }
    }
}

答案 1 :(得分:1)

您只需使用 predictedEndLocation 已经提供的 DragGesture.Value 即可计算隐含速度,而无需保持中间状态:

DragGesture()
.onChanged { value in 
    // Do something
}
.onEnded { value in
    let velocity = CGSize(
        width:  value.predictedEndLocation.x - value.location.x,
        height: value.predictedEndLocation.y - value.location.y
    )

    // Example

    if velocity.height > 500.0 {
        // Moving down fast
    }
}

答案 2 :(得分:0)

通过将最后一个拖动位置存储为状态,然后在调用onEnded时使用它来得出速度值,我已经能够获得相当不错的拖动速度值。

struct MyComponent: View {

    @State var lastDragPosition: DragGesture.Value?

    var body: some View {
        VStack{
            SomeOtherView()
        }.gesture(
            DragGesture().onChanged { value in
                self.lastDragPosition = value
            }
            .onEnded { value in
                let timeDiff = value.time.timeIntervalSince(self.lastDragPosition!.time)
                let speed:CGFloat = CGFloat(value.translation.height - self.lastDragPosition!.translation.height) / CGFloat(timeDiff)

                if(speed > 500) {
                    //Do Something
                }
            }
        )
    }
}

答案 3 :(得分:-3)

说实话,您甚至不需要速度。只需使用DragGesture.Value的{​​{1}}