colig
colig

Reputation: 395

Correctly detecting a swipe on a GridView placed inside a ViewPager in Android

I have a ViewPager which uses GridViews for pages. I would like the ViewPager to switch pages when I swipe across the screen.

The problem is that swipes are not detected when they are made across the GridView. Outside of the GridView, the swipes work correctly; it seems that the GridView is trapping all touch events without passing it to ViewPager first.

While fiddling with the source code, I did this to a custom class extended from GridView:

@Override
public boolean onTouchEvent(MotionEvent event) {
    return pager.onInterceptTouchEvent(event);
}

-- where pager refers to the ViewPager class. With this, ViewPager will correctly detect swipes and move pages accordingly, but it doesn't allow GridView to accept any events, so I can't click on the items.

What I would like to be able to do is correctly detect swipes in ViewPager and item clicks on GridView.

Upvotes: 6

Views: 4374

Answers (3)

Kevin
Kevin

Reputation: 83

I had trouble with colig's implementation, but I was able to get it to work by subclassing ViewPager and overriding the onInterceptTouchEvent() method. I only checked for swipes in the X direction to allow for vertical scrolling if necessary.

private static final int minSwipeDistance = 30;
private float mTouchX;

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    boolean response = super.onInterceptTouchEvent(event);
    float x = event.getX();
    switch (event.getActionMasked()) {
    case MotionEvent.ACTION_DOWN:
        mTouchX = x;
        break;
    case MotionEvent.ACTION_MOVE:
        float dX = Math.abs(x - mTouchX);
        if (dX > minSwipeDistance)
            return true;
        break;
    }
    return response;
}

Upvotes: 6

colig
colig

Reputation: 395

Alix is on the right track. I managed to come up with this simple-looking fix. I'm not entirely sure of how it works, but it does! And for future reference, it works for other kinds of views too -- TableLayout, for example -- not just GridView.

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    x = event.getX();
    y = event.getY();
    switch (event.getActionMasked()) {
    case MotionEvent.ACTION_DOWN: {
        downX = x;
        downY = y;
        return super.onInterceptTouchEvent(event);
    }
    case MotionEvent.ACTION_MOVE: {
        deltaX = Math.abs(downX - x);
        deltaY = Math.abs(downY - y);
        return super.onTouchEvent(event);
    }
    case MotionEvent.ACTION_UP: {
        if (deltaX > 4 && deltaY > 4) {
            super.onTouchEvent(event);
        }
    }
    }
    return super.onInterceptTouchEvent(event);
}

Upvotes: 2

Alix Bloom
Alix Bloom

Reputation: 217

You can override onInterceptTouchEvent for dispatch evenement where you want

Upvotes: 1

Related Questions