Synchronizing two ViewPagers using OnPageChangeListener

后端 未结 6 2033
北海茫月
北海茫月 2020-12-08 22:57

I\'m trying to synchronize two ViewPagers, as apparently have quite a lot of people before me, and I\'ve got as far as this:

private ViewPager m         


        
6条回答
  •  被撕碎了的回忆
    2020-12-08 23:47

    I had a similar issue, also needed to combine my syncing with animations in PageTransformer.

    Originally posted this answer here: https://stackoverflow.com/a/43638796/2867886

    But I will paste it here for convenience.

    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 advice is 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
            }
        }); 
    

提交回复
热议问题