Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get speed of a onTouch ACTION_MOVE event in Android

This should be a pretty simple thing to do. The user puts his finger on the screen and drags it around the screen. There are two events firing on onTouch:

  • MotionEvent.ACTION_DOWN
  • MotionEvent.ACTION_MOVE

Now, how can I calculate the speed of the ACTION_MOVE gesture ? The user drags the finger slower or faster during a gesture, so I think I need to calculate the speed between two intermediate touched points: the lastTouchedPointX,lastTouchedPointY and the event.getX(),event.getY().

Has anyone done this before ?

like image 262
Alin Avatar asked Apr 28 '11 08:04

Alin


3 Answers

What you need can be achieved by using the standard VelocityTracker class. More details on Google's Best Practice for User Input while tracking movement here. Most of the code below (which demonstrates the use of VelocityTracker by displaying the speed on X and Y axis of each fling/move) is taken from the previous resource link:

import android.os.Bundle;
import android.app.Activity;
import android.support.v4.view.VelocityTrackerCompat;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.widget.TextView;

public class MainActivity extends Activity {

    private VelocityTracker mVelocityTracker = null;
    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mTextView = new TextView(this);
        mTextView.setText("Move finger on screen to get velocity.");
        setContentView(mTextView);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int index = event.getActionIndex();
        int action = event.getActionMasked();
        int pointerId = event.getPointerId(index);

        switch (action) {
        case MotionEvent.ACTION_DOWN:
            if (mVelocityTracker == null) {

                // Retrieve a new VelocityTracker object to watch the velocity
                // of a motion.
                mVelocityTracker = VelocityTracker.obtain();
            } else {

                // Reset the velocity tracker back to its initial state.
                mVelocityTracker.clear();
            }

            // Add a user's movement to the tracker.
            mVelocityTracker.addMovement(event);
            break;
        case MotionEvent.ACTION_MOVE:
            mVelocityTracker.addMovement(event);
            // When you want to determine the velocity, call
            // computeCurrentVelocity(). Then call getXVelocity()
            // and getYVelocity() to retrieve the velocity for each pointer ID.
            mVelocityTracker.computeCurrentVelocity(1000);

            // Log velocity of pixels per second
            // Best practice to use VelocityTrackerCompat where possible.
            mTextView.setText("X velocity: "
                    + VelocityTrackerCompat.getXVelocity(mVelocityTracker,
                            pointerId)
                    + "\nY velocity: "
                    + VelocityTrackerCompat.getYVelocity(mVelocityTracker,
                            pointerId));
            break;
        case MotionEvent.ACTION_UP:
            break;
        case MotionEvent.ACTION_CANCEL:
            // Return a VelocityTracker object back to be re-used by others.
            mVelocityTracker.recycle();
            break;
        }
        return true;
    }

}
like image 198
Voicu Avatar answered Sep 23 '22 16:09

Voicu


@Override
        public boolean onTouchEvent(MotionEvent event, MapView mapView) {


            if(event.getAction() == MotionEvent.ACTION_DOWN) {

                oldX = event.getX();
                oldY = event.getY();
                    //start timer

            } else if (event.getAction() == MotionEvent.ACTION_UP) {   

                //long timerTime = getTime between two event down to Up
                newX = event.getX();
                newY = event.getY();

                float distance = Math.sqrt((newX-oldX) * (newX-oldX) + (newY-oldY) * (newY-oldY));
                float speed = distance / timerTime;

            }
}
like image 28
Dharmendra Avatar answered Sep 23 '22 16:09

Dharmendra


It's a question about how accurate you want to perform this calculation.

However the basic procedure is to get the timestamp of each corresponding ACTION_DOWN, ACTION_UP couple and calculate the difference.

Then you need to determine the covered pixels. This could be done with simple trigonometry.

When you have both time difference and covered pixels you can calculate the pixels per time speed as an average of the two points (down and up).

You can do this for every point when the finger is moving over the screen to get a better result.

like image 24
UpCat Avatar answered Sep 19 '22 16:09

UpCat