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