Android 2 ViewPagers simultanious滚动

时间:2014-08-08 15:10:40

标签: android android-viewpager

是否有可能同时滚动两个ViewPagers,如果我开始滚动一个,另一个执行完全相同的滚动行为。或者我应该实现除ViewPager之外的其他东西。

谢谢

4 个答案:

答案 0 :(得分:3)

你可以给每个人OnPageChangeListsner并实施onPageScrolled(当你在不滚动的情况下更改页面时也可以onPageSelected)。由于逻辑相同,我们可以为此编写一个类:

public class ViewPagerScrollSync implements ViewPager.OnPageChangeListener {
    private ViewPager actor; // the one being scrolled
    private ViewPager target; // the one that needs to be scrolled in sync

    public ViewPagerScrollSync(ViewPager actor, ViewPager target) {
        this.actor = actor;
        this.target = target;
        actor.setOnPageChangeListener(this);
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        if (actor.isFakeDragging()) {
            return;
        }

        if (state == ViewPager.SCROLL_STATE_DRAGGING) {
            // actor has begun a drag
            target.beginFakeDrag();
        } else if (state == ViewPager.SCROLL_STATE_IDLE) {
            // actor has finished settling
            target.endFakeDrag();
        }
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if (actor.isFakeDragging()) {
            return;
        }
        if (target.isFakeDragging()) {
            // calculate drag amount in pixels.
            // i don't have code for this off the top of my head, but you'll probably
            // have to store the last position and offset from the previous call to
            // this method and take the difference.
            float dx = ...
            target.fakeDragBy(dx);
        }
    }

    @Override
    public void onPageSelected(int position) {
        if (actor.isFakeDragging()) {
            return;
        }

        // Check isFakeDragging here because this callback also occurs when
        // the user lifts his finger on a drag. If it was a real drag, we will
        // have begun a fake drag of the target; otherwise it was probably a
        // programmatic change of the current page.
        if (!target.isFakeDragging()) {
            target.setCurrentItem(position);
        }
    }
}

然后在你的Activity / Fragment中,你会这样做:

ViewPager pager1 = ...
ViewPager pager2 = ...
ViewPagerScrollSync sync1 = new ViewPagerScrollSync(pager1, pager2);
ViewPagerScrollSync sync2 = new ViewPagerScrollSync(pager2, pager1);

答案 1 :(得分:1)

您需要密切关注您的位置,以避免IndexOutOfBounds错误。一般为:

        viewPager1.setOnPageChangeListener(new OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            viewPager2.setCurrentItem(position);

        }

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onPageScrollStateChanged(int state) {
            // TODO Auto-generated method stub

        }
    });

假设两个ViewPagers具有相同数量的项目,这将起作用。否则,您需要跟踪您的位置以同步两个寻呼机的行为。

澄清一下:如果您的Adapters项目数量不同,或者您不希望两个寻呼机的行为完全相同,则需要检查viewPager1的位置。 onPageSelected()方法,然后调整位置以转到setCurrentItem()

viewPager2方法

答案 2 :(得分:1)

对我来说最有效的解决方案是在MotionEvent实例之间的OnTouchListener中传递ViewPager。试过假拖动,但它总是滞后和马车(尝试了这个线程的解决方案 - 没有工作) - 我需要一个平滑,视差效果。

所以,我的建议是实施View.OnTouchListener。必须缩放MotionEvent以补偿宽度的差异。

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;
}
}

然后将其设置为ViewPager

    sourcePager.setOnTouchListener(new SyncScrollOnTouchListener(targetPager));

请注意,此解决方案仅在两个寻呼机具有相同方向时才有效。如果您需要它可以用于不同的方向 - 调整syncEvent Y坐标而不是X。

还有一个问题需要考虑 - 最小投掷速度和距离只会导致一个寻呼机更改页面。

可以通过向我们的寻呼机添加OnPageChangeListener轻松修复

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

答案 3 :(得分:0)

将此类放在您的项目中

import androidx.viewpager.widget.ViewPager;
/**
 * Sync Scroll 2 View Pager
 */
public class SyncScrollOnTouchListener implements ViewPager.OnPageChangeListener {

    private ViewPager master;
    private ViewPager slave;
    private int mScrollState = ViewPager.SCROLL_STATE_IDLE;

    public SyncScrollOnTouchListener(ViewPager master, ViewPager slave){
        this.master = master;
        this.slave = slave;
    }

    @Override
    public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
        if (mScrollState == ViewPager.SCROLL_STATE_IDLE) {
            return;
        }
        this.slave.scrollTo(this.master.getScrollX()*
                this.slave.getWidth()/
                this.master.getWidth(), 0);
    }

    @Override
    public void onPageSelected(final int position) {

    }

    @Override
    public void onPageScrollStateChanged(final int state) {
        mScrollState = state;
        if (state == ViewPager.SCROLL_STATE_IDLE) {
            this.slave.setCurrentItem(this.master
                    .getCurrentItem(), false);
        }
    }
}

用法

现在您可以同步查看页面的页面更改

masterPager .addOnPageChangeListener(newSyncScrollOnTouchListener( masterPager ,slavePager));

    //Sync Scroll of Pages
  
    leftPanelPager.addOnPageChangeListener(new SyncScrollOnTouchListener(leftPanelPager,rightPanelPager));
    rightPanelPager.addOnPageChangeListener(new SyncScrollOnTouchListener(rightPanelPager,leftPanelPager));