Fling gesture detection on grid layout

android, gesture-recognition, listener

Solution

Thanks to Code Shogun, whose code I adapted to my situation.

Let your activity implement`OnClickListener` as usual:

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(this, 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 {
        if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
          return false;
        // right to left swipe
        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;
    }

    @Override
    public boolean onDown(MotionEvent e) {
      return true;
    }
  }
}

Attach your gesture listener to all the views you add to the main layout;

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

Watch in awe as your overridden methods are hit, both the `onClick(View v)` of the activity and the `onFling` of the gesture listener.

public void onClick(View v) {
  Filter f = (Filter) v.getTag();
  FilterFullscreenActivity.show(this, input, f);
}

The post 'fling' dance is optional but encouraged.

Problem

I want to get `fling` gesture detection working in my Android application. What I have is a `GridLayout` that contains 9 `ImageView`s. The source can be found here: Romain Guys's Grid Layout. That file I take is from Romain Guy's Photostream application and has only been slightly adapted. For the simple click situation I need only set the `onClickListener` for each `ImageView` I add to be the main `activity` which implements `View.OnClickListener`. It seems infinitely more complicated to implement something that recognizes a `fling`. I presume this is because it may span `views`? If my activity implements `OnGestureListener` I don't know how to set that as the gesture listener for the `Grid` or the `Image` views that I add. ``` public class SelectFilterActivity extends Activity implements View.OnClickListener, OnGestureListener { ... ``` If my activity implements `OnTouchListener` then I have no `onFling` method to `override` (it has two events as parameters allowing me to determine if the fling was noteworthy). ``` public class SelectFilterActivity extends Activity implements View.OnClickListener, OnTouchListener { ... ``` If I make a custom `View`, like `GestureImageView` that extends `ImageView` I don't know how to tell the activity that a `fling` has occurred from the view. In any case, I tried this and the methods weren't called when I touched the screen. I really just need a concrete example of this working across views. What, when and how should I attach this `listener`? I need to be able to detect single clicks also. ``` // Gesture detection mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() { public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { int dx = (int) (e2.getX() - e1.getX()); // don't accept the fling if it's too short // as it may conflict with a button push if (Math.abs(dx) > MAJOR_MOVE && Math.abs(velocityX) > Math.absvelocityY)) { if (velocityX > 0) { moveRight(); } else { moveLeft(); } return true; } else { return false; } } }); ``` Is it possible to lay a transparent view over the top of my screen to capture flings? If I choose not to `inflate` my child image views from XML can I pass the `GestureDetector` as a constructor parameter to a new subclass of `ImageView` that I create? This is the very simple activity that I'm trying to get the `fling` detection to work for: SelectFilterActivity (Adapted from photostream). I've been looking at these sources: Detect Gestures - Tutorial SDK docs Calculator Code Nothing has worked for me so far and I was hoping for some pointers.

Original source