Home » Android » Vertical and Horizontal gestures in Android

Vertical and Horizontal gestures in Android

Posted by: admin June 15, 2020 Leave a comment

Questions:

I would like my GestureOverlayView to detect both purely horizontal as well as vertical gestures.

From http://android-developers.blogspot.com/2009/10/gestures-on-android-16.html

“orientation: indicates the scroll orientation of the views underneath. In this case the list scrolls vertically, which means that any horizontal gestures (like action_delete) can immediately be recognized as a gesture. Gestures that start with a vertical stroke must contain at least one horizontal component to be recognized. In other words, a simple vertical line cannot be recognized as a gesture since it would conflict with the list’s scrolling.”

Seems like a catch-22, if the android:orientation is set to vertical, I can only have horizontal swipes, and if the android:orientation is set to horizontal, I can only have vertical swipes.
How can I get around this requirement?

How to&Answers:

I had run into this problem at a hackathon. There’s no way you can solve it with GestureOverlayView, so you have to use motion events. GestureOverlayView however works with slightly more “detailed” gestures, like a circle. What I’ve noticed is that GestureOverlayView best works for closed figures. So, motionEvent sensor it is. I found the code here. I modified Gav’s answer for vertical swipes too. Haven’t tested it though, but positive that it should work.

Here’s an example:

public class SelectFilterActivity extends Activity implements OnClickListener
{

private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 250;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
private GestureDetector gestureDetector;
View.OnTouchListener gestureListener;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    /* ... */

    // Gesture detection
    gestureDetector = new GestureDetector(new MyGestureDetector());
    gestureListener = new View.OnTouchListener() {
        public boolean onTouch(View v, MotionEvent event) {
            return gestureDetector.onTouchEvent(event);
        }
    };

}

class MyGestureDetector extends SimpleOnGestureListener {
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        try {
            // downward swipe
            if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY)
                Toast.makeText(SelectFilterActivity.this, "Downward Swipe", Toast.LENGTH_SHORT).show();
 else if (Math.abs(e2.getY() - e1.getY()) > SWIPE_MAX_OFF_PATH && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY)
                Toast.makeText(SelectFilterActivity.this, "Upward Swipe", Toast.LENGTH_SHORT).show();
            // right to left swipe
            else if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                Toast.makeText(SelectFilterActivity.this, "Left Swipe", Toast.LENGTH_SHORT).show();
            }  else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                Toast.makeText(SelectFilterActivity.this, "Right Swipe", Toast.LENGTH_SHORT).show();
            }
        } catch (Exception e) {
            // nothing
        }
        return false;
    }

}

Now add it to the views where you’d like gesture detection,

// Do this for each view added to the grid
    imageView.setOnClickListener(SelectFilterActivity.this); 
    imageView.setOnTouchListener(gestureListener);

Cheers to Gav for the code!

Answer:

All you have to do, is set the GestureStrokeAngleThreshold to a value closer to 90 (I used 90f)

The default value of the angle threashold is 40.0f because of which your simple vertical gestures would be skipped

Answer:

Maybe not the best way to go about it, but you could override the default behavior by extending GestureOverlayView

You’d need to override the private Rect touchMove(MotionEvent event) method and get rid of the orientation check:

if (box.squareness > mGestureStrokeSquarenessTreshold ||
    (mOrientation == ORIENTATION_VERTICAL ?
        angle < mGestureStrokeAngleThreshold :
        angle > mGestureStrokeAngleThreshold)) {

    mIsGesturing = true;
    ...
    ...
}

It’s the only place where the orientation is used at all, so no need for extensive modifications. Just a simple extend/override.

Of course, to do it right, you’d add an ORIENTATION_NONE and check against that, like they did for the Replicant Project, but I guess that depends on if you’ll ever need the functionality again.

Answer:

Have you seen http://developer.android.com/training/gestures/index.html ? I need a little more information about what you are trying to do with the horizontal and vertical gestures to give more specific advice. But having a touch area that does one thing with horizontal swipes and another thing with vertical swipes is definitely possible. It’s important to also not that you are looking for perfectly straight lines, as your users won’t be able to make them.

Edit (1):
Have you seen http://www.vogella.com/articles/AndroidGestures/article.html ? Vogella seems to be implying with his example that you can have an up gesture and sideways gestures in the GestureOverlayView. Is this what you are trying to do?