8

I have an Activity which holds a single Fragment:

getFragmentManager().beginTransaction().add(android.R.id.content, fragment1).commit();

My question is, how can i detect gestures? I tried with OnTouchListener, also with onInterceptTouchEvent method. Basically i want to detect swipes. My SwipeGestureDetector looks like this:

public class SwipeGestureDetector extends SimpleOnGestureListener {

    // ...

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

    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;

            if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                // right to left swipe

            } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                // left to right swipe

            }
        } catch (Exception e) {
            // nothing
        }
        return false;
    }
}

Then i register it in my Activity:

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

        SwipeGestureDetector swipeDetector = new SwipeGestureDetector();
        final GestureDetector detector = new GestureDetector(this, swipeDetector);
        findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return detector.onTouchEvent(event);
            }
        });
    }

Unfortunetaly no swipe gesture is detected. How can i achieve this? Please do not suggest to use ViewPager, i cannot use it.

WonderCsabo
  • 11,947
  • 13
  • 63
  • 105

3 Answers3

4

Here is the workaround which i made for this problem.

I had to override dispatchTouchEvent() method in my Activity. This gets called when a touch event occurs to the window.

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    boolean handled = swipeDetector.onTouchEvent(ev);
    if (!handled) {
        return super.dispatchTouchEvent(ev);
    }

    return handled;
}
WonderCsabo
  • 11,947
  • 13
  • 63
  • 105
0

WonderCsabo's Answer didn't exactly work for me. The problem I had with that code was that inside my activity I had a view pager and a fragment with several clickable views inside of it. None of the click or swipe handlers were called with that code so it broke my stuff. Apparently handled was true too often. so the if (!handled) blocked the pager and fragment from receiving their touch events.

So I tried just taking out the if statement and now it seems to work. Here is the activity class. Its got a view pager and a fragment

public class MyActivity extends Activity  {

private SectionsPagerAdapter sectionsPagerAdapter;
private ViewPager viewPager;
ArrayList<Class> tabsFragmentClasses = new ArrayList<Class>();
private GestureDetector gestureDetector;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.ride_detail_activity);

    viewPager = (ViewPager) findViewById(R.id.pager);

    if (savedInstanceState == null) {
        getFragmentManager().beginTransaction()
                .add(R.id.container, new MyFragment(),"MyFragment")
                .commit();
    }

    gestureDetector = new GestureDetector(this,gestureListener);
}

GestureDetector.SimpleOnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener(){
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        final int SWIPE_MIN_DISTANCE = 120;
        final int SWIPE_MAX_OFF_PATH = 250;
        final int SWIPE_THRESHOLD_VELOCITY = 200;
        try {
            if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
                return false;
            if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE
                    && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                Log.i("Tag", "Right to Left");
            } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE
                    && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
                Log.i("Tag", "Left to Right");
            }
        } catch (Exception e) {
            // nothing
        }
        return false;
    }

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

Now if I complete this like the Android Detecting Common Gestures Docs explain I add this code.

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

The problem is that the gesture detector only works where there are no touch enabled views like my view pager and buttons. By using this code instead

@Override
public boolean dispatchTouchEvent(MotionEvent event){
    this.gestureDetector.onTouchEvent(event);
    return super.dispatchTouchEvent(event);
}

Then what happens is the views in fragment and the view pager do get all touch events just as they normally do but I also get gesture events in my listener.

Community
  • 1
  • 1
Marc
  • 1,159
  • 17
  • 31
0

I just overrided GestureListener#onDown() method to return true

theroom101
  • 599
  • 1
  • 9
  • 23