Android 2浏览页面同时滚动

Android 2浏览页面同时滚动,android,android-viewpager,Android,Android Viewpager,有没有可能有两个同时滚动的ViewPagers,如果我开始滚动其中一个,另一个会执行完全相同的滚动行为。或者我应该实现除ViewPager之外的其他功能 谢谢您需要密切关注您的位置,以避免出现索引自动边界错误。一般来说: viewPager1.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int position)

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


谢谢

您需要密切关注您的位置,以避免出现
索引自动边界
错误。一般来说:

        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

        }
    });
假设两个
查看页面
具有相同的项目数,则此操作将起作用。否则,您将需要跟踪您的位置以同步两个寻呼机的行为


澄清:如果
适配器的项数不同,或者您不希望两个寻呼机的行为完全相同,则需要在
onPageSelected()
方法中检查
viewPager1
的位置,然后调整位置以传递到
setCurrentItem()
查看页面2的方法

您可以给每个人一个
onpagechangelistner
,并实现
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);
        }
    }
}
然后在活动/片段中,您将执行以下操作:

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

最适合我的解决方案是在
OnTouchListener
实例之间传递
MotionEvent
。尝试了假拖拽,但总是拖拉和拖拉(也尝试了这个线程的解决方案-不起作用)-我需要一个平滑的、类似视差的效果

因此,我的建议是实现一个
视图.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));
请注意,只有当两个寻呼机的方向相同时,此解决方案才会起作用。如果需要它在不同方向上工作-调整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
        }
    }); 

在项目中删除此类

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


粘贴布局xml代码我还没有,我还在研究一种方法,谢谢你在第一个片段中使用OnPageChangeListener,并将其与第二个ViewPager同步。这不是选择页面时唯一的触发器吗?我希望在开始滚动时,另一个视图也会启动,所以它看起来有点像一个镜像效应,这一切都可以通过
OnPageChangeListener
实现。请查阅有关这方面的文档,这些文档看起来不错,我现在就试试。我已经添加了一些对
actor.isfakedraging()
的检查,以防止周期性回调。你应该尝试一下,看看它们是否必要。你们真的成功地使用了这个吗?我试过了,但是它在两个浏览页面之间总是不同步。这是一个很好的、优雅的解决方案。有两件事需要补充:一是我在使用
target.isfakedraging
而不是
时实现了这一点!target.isfakedrawing
onPageScrolled
中;另一个原因是,
onPageScrolled
方法似乎在
目标
的伪拖动仍然存在时被调用。这会导致
目标
切换到正确的位置,但一旦拖动结束,就会切换回它开始的位置(如果“向前滚动”)。为了避免上一个问题,我为
参与者
添加了一个
endFakeDrag
setCurrentItem
,在
onPageSelected
中,当参与者进行假拖动并添加了一个
目标时。IsFakeDraging
检入
onPageScrollStateChanged
以便在非假拖动时不调用
endFakeDrag
    //Sync Scroll of Pages
  
    leftPanelPager.addOnPageChangeListener(new SyncScrollOnTouchListener(leftPanelPager,rightPanelPager));
    rightPanelPager.addOnPageChangeListener(new SyncScrollOnTouchListener(rightPanelPager,leftPanelPager));