Android Fling Detection

I found existing tutorials on how to do this to be a bit complicated. Here's how to do simple fling detection in four directions:
public interface FlingListener {
  void onTopToBottom();
  void onBottomToTop();
  void onLeftToRight();
  void onRightToLeft();
}

public class FlingDetector {
  static final int SWIPE_MIN_DISTANCE = 120;
  static final int SWIPE_MAX_OFF_PATH = 250;
  static final int SWIPE_THRESHOLD_VELOCITY = 200;
  
  private final GestureDetector gestureDetector;

  public FlingDetector(final FlingListener listener) {
    gestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener() {
      @Override
      public boolean onFling(MotionEvent e1, MotionEvent e2,
          float velocityX, float velocityY) {
        if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) {
          if (Math.abs(e1.getX() - e2.getX()) > SWIPE_MAX_OFF_PATH
              || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) {
            return false;
          }
          if (e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE) {
            listener.onBottomToTop();
          } else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE) {
            listener.onTopToBottom();
          }
        } else {
          if (Math.abs(velocityX) < SWIPE_THRESHOLD_VELOCITY) {
            return false;
          }
          if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE) {
            listener.onRightToLeft();
          } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE) {
            listener.onLeftToRight();
          }
        }
        return true;

      }
    });
  }
  
  public boolean onTouchEvent(MotionEvent event) {
    return gestureDetector.onTouchEvent(event);
  }
}

public class MainActivity extends Activity {
  private FlingDetector flingDetector;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    flingDetector = new FlingDetector(new FlingListener() {
      @Override
      public void onTopToBottom() {

      }

      @Override
      public void onRightToLeft() {

      }

      @Override
      public void onLeftToRight() {

      }

      @Override
      public void onBottomToTop() {

      }
    });
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    if (flingDetector.onTouchEvent(event)) {
      return true;
    }
    return super.onTouchEvent(event);
  }
}

3 comments:

  1. Nice example, thank you! Only problem I had with the code is that you need an onDown handler that returns true so the event will get propagated to the onFling handler -- until I found that nothing worked. So I added the following just before your onFling method:

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

    See my source here: http://stackoverflow.com/questions/4522637/android-onfling-not-responding. The original poster there had an onDown handler that returned false, but it seems to be an issue also if you omit the onDown handler altogether.

    Thanks again for a nice, concise example!

    ReplyDelete
  2. Ok thanks for sharing. Didnn't get it to work using this example as is plus the ondown override. Use the FlingDetector as a delegate in the activity and override the ontouch event.
    And adds the ondown just before onFling in the FlingDetector. I want to apply this to a scrollview. What have i forgot here? Thanks in advance.

    ReplyDelete