是否有可能同时滚动两个ViewPagers
,如果我开始滚动一个,另一个执行完全相同的滚动行为。或者我应该实现除ViewPager之外的其他东西。
谢谢
答案 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));