开发者

Android viewpager synchronized scrolling

I have two ViewPagers -- Pager1 and Pager2. I added an OnPageChangeListener to Pager1 and in the onPageScrolled callback, I call Pager2.scrollTo(x, y) to move it. Both of the ViewPagers开发者_Python百科 do scroll smoothly and are synchronized, but the problem is that the contents of Pager2 do not change. I checked it with LogCat -- instantiateItem() for Pager2 doesn't get called at all.

As a workaround, I added Pager2.setCurrentItem() to the onPageSelected() callback for Pager1. While this does scroll both Views, it's not synchronized to the pixel. I'm wondering if there's a way to achieve this effect without having to override the actual ViewPager class.


The solution that worked best for me was to pass MotionEvent in OnTouchListener between ViewPager instances. Tried fake dragging but it was always laggy and buggy - I needed a smooth, parallax-like effect.

So, my solution was to implement a View.OnTouchListener. The MotionEvent has to be scaled to compensate for the difference in width.

public class SyncScrollOnTouchListener implements View.OnTouchListener {

private final View syncedView;

public SyncScrollOnTouchListener(@NonNull View syncedView) {
    this.syncedView = syncedView;
}

@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
    MotionEvent syncEvent = MotionEvent.obtain(motionEvent);
    float width1 = view.getWidth();
    float width2 = syncedView.getWidth();

    //sync motion of two view pagers by simulating a touch event
    //offset by its X position, and scaled by width ratio
    syncEvent.setLocation(syncedView.getX() + motionEvent.getX() * width2 / width1,
            motionEvent.getY());
    syncedView.onTouchEvent(syncEvent);
    return false;
}
}

Then set it to your ViewPager

    sourcePager.setOnTouchListener(new SyncScrollOnTouchListener(targetPager));

Note that this solution will only work if both pagers have the same orientation. If you need it to work for different orientations - adjust syncEvent Y coordinate instead of X.

There is one more issue that we need to take into account - minimum fling speed and distance that can cause just one pager to change page.

It can be easily fixed by adding an OnPageChangeListener to our pager

sourcePager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset,
                                   int positionOffsetPixels) {
            //no-op
        }

        @Override
        public void onPageSelected(int position) {
            targetPager.setCurrentItem(position, true);
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            //no-op
        }
    }); 


Have you tried beginFakeDrag()?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜