8

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?

RobinHood
  • 10,897
  • 4
  • 48
  • 97
Bashevis
  • 1,507
  • 16
  • 21
  • Nope, there still isn't any solution for Android... – Bashevis Jan 10 '13 at 00:14
  • Geez, so how do I do what I need to? I really need to do this. This tutorial shows up and down being made in Gestures Builder http://www.vogella.com/articles/AndroidGestures/article.html, although not used. Here is my own question, if you want to have a look, http://stackoverflow.com/questions/14246998/detecting-vertical-gestures. It doesn't make sense that there is no way to do this, other apps use this kind of functionality all the time. – capcom Jan 10 '13 at 01:01

4 Answers4

7

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!

halfer
  • 19,824
  • 17
  • 99
  • 186
Karthik Balakrishnan
  • 4,353
  • 6
  • 37
  • 69
  • I already had this done in my code, but thanks for your answer. The thing is, I want all the purely vertical and horizontal gestures, along with anything I design from gestureoverlayview. Sure, you can hack around with motionevents to detect a circle and such, but it's a real pain. I don't see why this is so hard to do in Android. Anyhow, +1 for a good answer. I think I will end up sticking with GestureDetector for now, and implementing some of my own multifinger gestures to add extra functionality gesture-wise. – capcom Jan 13 '13 at 14:07
  • Also note that when I offered the bounty, I specifically mentioned that the answer must not include GestureDetector. But many thanks nonetheless. – capcom Jan 13 '13 at 14:08
  • @capcom Anytime, but do let me know if you can get the gestureOverlayView to work. I tried a lot, had to make more complex gestures, simple swipes don't seem to work. – Karthik Balakrishnan Jan 13 '13 at 14:10
  • Yes, I totally agree with you. I'm sure there is some way to get it to work, but time is too precious. I've already spent an entire day trying to make something work. After spending that much time, it's time to look for workarounds and substitutions. I'm sticking with GestureDetector, and capturing any multifinger gestures before passing it off to the GestureDetector. Gives me about 8-12 unique gestures I can work with. Although I really did want the "O" gesture. – capcom Jan 13 '13 at 14:15
  • @capcom - Could I see the code for your custom gestures? If you're willing, you can send em to my mail. torcellite@gmail.com – Karthik Balakrishnan Jan 13 '13 at 14:38
  • I mean, it's just using the GestureOverlayView class and using the gestures file from Gesture Builder - pretty commonplace. Is that what you're looking for, or something else? I followed this article btw, vogella.com/articles/AndroidGestures/article.html. – capcom Jan 13 '13 at 15:22
  • Ah, just a gesture raw file? I thought it would be with motion events, thanks anyway. – Karthik Balakrishnan Jan 13 '13 at 15:26
  • Check out http://code.google.com/p/android-multitouch-controller/ As well as http://code.google.com/p/markers-for-android/wiki/DeviceSupport. Great examples of how you can use multitouch gestures in your app, as well as 'pressure' sensing. Adds several ways to receive user input for your app. – capcom Jan 13 '13 at 16:29
  • Thank you so much, It worked well on lollipop, but I had to remove Math.abs() from the vertical distance to catcn the up and down swipes. – Hermandroid Jun 18 '16 at 04:20
5

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

Sagar Sodah
  • 112
  • 1
  • 6
0

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.

Geobits
  • 22,218
  • 6
  • 59
  • 103
0

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?

Dandre Allison
  • 5,975
  • 5
  • 42
  • 56
  • I've already seen that link. What I am trying to do is fairly simple: I want to use custom gestures from the GestureOverlayView class, along with vertical and horizontal gestures. That class, however, does not allow 'purely' horizontal/vertical gestures because it interprets those actions as scrolling (afaik). I do not have any scrollable containers in my view. By purely vertical/horizontal, I don't actually mean that the lines have to perfectly straight. Just roughly. I'm not asking the user to do anything unnatural. Thanks. – capcom Jan 16 '13 at 12:34
  • My question, is the use of the 2 gestures. There's a `GestureDetector` that can recognize scroll gestures, which horizontal and vertical swipes are (even when you aren't scrolling the content of a container). There's touch interception that means a containing view can keep the motion events for itself in some situations and pass them along to a child view in other situations. – Dandre Allison Jan 16 '13 at 16:27
  • The complexity of what you want to do is related to the fact that you can't expect straight lines from the user. I wasn't accusing you of wanting to. Nevertheless, it means that "detecting" gestures needs to be restrictive so that it can be certain of a gesture while allowing a user to make rough strokes. – Dandre Allison Jan 16 '13 at 16:31