Saad Farooq
Saad Farooq

Reputation: 13402

Android - ViewPager scrolling resets

I'm using a ViewPager in my app that houses a horizontal layout of images to implement a Paginated gallery.

When I test the view alone, i.e. as the main view of an activity, it works fine. However, when I include this as part of another layout, the scrolling (or flicking) becomes weird. If seems to reset to its original position around halfway through a swipe (really quick flicks are the only thing I've gotten to work so far).

Any ideas what the problem could be ?

Just in case it is of any relevance, the view is inflated from XML and added in a PagerAdapter inherited class.

Upvotes: 6

Views: 2773

Answers (1)

Brian Dupuis
Brian Dupuis

Reputation: 8176

Yeah, ViewPager and other scrolling items don't play well together by default. When I have to do such things, I typically subclass ViewPager to make something that's aware of children that can scroll. Then in my onInterceptTouchEvent() I check whether the hit rect is within that child and don't intercept the touch event so the child has a whack at it. Something like this:

/**
 * Override to not intercept touch events within our scroller if it exists.
 */
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    if(scrollerId != 0) {
        View scroller = findViewById(scrollerId);
        if(scroller != null) {
            Rect rect = new Rect();
            scroller.getHitRect(rect);
            if(rect.contains((int)ev.getX(), (int)ev.getY())) {
                return false;
            }
        }
    }
    return super.onInterceptTouchEvent(ev);
}

Then all you need is a way to set that scrollerId (a simple public method works).

Note another way is if you are using a ScrollView for vertically scrolling elements with ViewPager children, you'll need to go a different direction. Have a subclass of ScrollView that detects vertical scrolling directions and bails for horizontal scrolling so the ViewPager picks it up.

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            xDistance = yDistance = 0f;
            lastX = ev.getX();
            lastY = ev.getY();
            break;
        case MotionEvent.ACTION_MOVE:
            final float curX = ev.getX();
            final float curY = ev.getY();
            xDistance += Math.abs(curX - lastX);
            yDistance += Math.abs(curY - lastY);
            lastX = curX;
            lastY = curY;
            if (xDistance > yDistance)
                return false;
    }

    return super.onInterceptTouchEvent(ev);
}

Upvotes: 9

Related Questions