Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate velocity of DragGesture

Tags:

ios

swift

swiftui

I would like to extract the velocity of a DragGesture to use for the initialVelocity parameter of a spring animation. I am trying to create a movable card that has a responsive spring animation like that found in the Apple Maps app.

I have tried calculating velocity by dividing the height of the drag translation by the total time elapsed of the drag gesture.

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

The problem is that when a user begins a drag they may slow down the drag before flicking and releasing, which causes the velocity to be very slow since a long period of time has elapsed. If possible, I'd only like to calculate velocity using data from the final milliseconds of the drag gesture.

like image 961
langio Avatar asked Jul 26 '19 15:07

langio


2 Answers

I've been able to get a pretty decent drag velocity value by storing the last drag position as a state and then using that to derive a speed value when the onEnded gets called.

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
                }
            }
        )
    }
}
like image 156
Tom Millard Avatar answered Oct 22 '22 05:10

Tom Millard


You can compute the implied velocity without keeping intermediate state simply by using the predictedEndLocation already supplied by the 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
    }
}
like image 10
dbart Avatar answered Oct 22 '22 05:10

dbart