永发信息网

如何实现两个ViewPager的联动

答案:1  悬赏:80  手机版
解决时间 2021-02-27 23:23
如何实现两个ViewPager的联动
最佳答案
联动ViewPager的意思就是当一个viewpager在滑动的时候,另外一个ViewPager也跟着滑动,而且两者是同步的。

如果ViewPager有关于移动距离的回调接口,这事儿就好办了,遗憾的是没有,只有一个OnPageChangeListener,我试过在OnPageChangeListener中根据onPageScrolled(int
position, float positionOffset, int positionOffsetPixels)的参数来做,但是失败了。

那就只有自定义ViewPager了。

我直接将ViewPager的源码冲v4中拿出来,去掉不必要的一些东西,直到不会再出现找不到类为止,

除了需要将ViewPager拿出来之外,还需要把相关的PagerAdapter类也拿出来,不然ViewPager使用的是自己的而adapter用的是v4中的,可能会出问题。

为了实现联动,在ViewPager中增加一个private变量mFollowViewPager(同时增加变量的set方法):
private ViewPager mFollowViewPager;
public void setFlolwViewPager(ViewPager page){
mFollowViewPager = page;
}
我的想法是在当前ViewPager滚动的相关代码处,调用mFollowViewPager的scrollTo方法。

那么在哪里加入比较好呢,经过仔细跟踪ViewPager的行为,我发现当手指未松开的时候,performDrag方法处理相关的移动,他调用了自己的scrollTo来实现自身的平移,因此我们只需要在performDrag方法中加入如下代码://add by jcodecraeer
final float pageOffset = scrollX / width;
if(mFollowViewPager!=null){
mFollowViewPager.scrollTo( (int)(pageOffset*mFollowViewPager.getWidth()), mFollowViewPager.getScrollY());
}

注意,并不是主ViewPager移动了多远,mFollowViewPager就移动多远,因为两个ViewPager的宽度可能不一样,所以需要转换一下,上面的代码中final float pageOffset = scrollX / width;pageOffset
就只转换得到的值。

改写后的performDrag如下:
private boolean performDrag(float x) {
boolean needsInvalidate = false;

final float deltaX = mLastMotionX - x;
mLastMotionX = x;

float oldScrollX = getScrollX();
float scrollX = oldScrollX + deltaX;
final int width = getWidth();

float leftBound = width * mFirstOffset;
float rightBound = width * mLastOffset;
boolean leftAbsolute = true;
boolean rightAbsolute = true;

final ItemInfo firstItem = mItems.get(0);
final ItemInfo lastItem = mItems.get(mItems.size() - 1);
if (firstItem.position != 0) {
leftAbsolute = false;
leftBound = firstItem.offset * width;
}
if (lastItem.position != mAdapter.getCount() - 1) {
rightAbsolute = false;
rightBound = lastItem.offset * width;
}

if (scrollX < leftBound) {
if (leftAbsolute) {
float over = leftBound - scrollX;
needsInvalidate = mLeftEdge.onPull(Math.abs(over) / width);
}
scrollX = leftBound;
} else if (scrollX > rightBound) {
if (rightAbsolute) {
float over = scrollX - rightBound;
needsInvalidate = mRightEdge.onPull(Math.abs(over) / width);
}
scrollX = rightBound;
}
// Don't lose the rounded component
mLastMotionX += scrollX - (int) scrollX;
scrollTo((int) scrollX, getScrollY());
pageScrolled((int) scrollX);
//add by jcodecraeer
final float pageOffset = scrollX / width;
if(mFollowViewPager!=null){
mFollowViewPager.scrollTo( (int)(pageOffset*mFollowViewPager.getWidth()), mFollowViewPager.getScrollY());
}
return needsInvalidate;
}

光处理了手指未离开屏幕阶段的平移还不够,手指松开了,ViewPager还会自己继续一定一段距离,因此mFollowViewPager也应该跟着移动,我们想下,手指松开是不是该在 case MotionEvent.ACTION_UP中处理的呢?

我们找到相关代码:
case MotionEvent.ACTION_UP:
if (mIsBeingDragged) {
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
velocityTracker, mActivePointerId);
mPopulatePending = true;
final int width = getWidth();
final int scrollX = getScrollX();
final ItemInfo ii = infoForCurrentScrollPosition();
final int currentPage = ii.position;
final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
final int activePointerIndex =
MotionEventCompat.findPointerIndex(ev, mActivePointerId);
final float x = MotionEventCompat.getX(ev, activePointerIndex);
final int totalDelta = (int) (x - mInitialMotionX);
int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
totalDelta);
setCurrentItemInternal(nextPage, true, true, initialVelocity);

mActivePointerId = INVALID_POINTER;
endDrag();
needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
}
可以看到setCurrentItemInternal中调用了scrollToItem(item, smoothScroll, velocity, dispatchSelected);来实现手指松开后的继续平移效果。也就是说对于mFollowViewPager,如果我们也同样调用setCurrentItemInternal就可以使他也跟着移动了。照着这个思路我们改写case
MotionEvent.ACTION_UP的代码段:case MotionEvent.ACTION_UP:
if (mIsBeingDragged) {
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int initialVelocity = (int) VelocityTrackerCompat.getXVelocity(
velocityTracker, mActivePointerId);
mPopulatePending = true;
final int width = getWidth();
final int scrollX = getScrollX();
final ItemInfo ii = infoForCurrentScrollPosition();
final int currentPage = ii.position;
final float pageOffset = (((float) scrollX / width) - ii.offset) / ii.widthFactor;
final int activePointerIndex =
MotionEventCompat.findPointerIndex(ev, mActivePointerId);
final float x = MotionEventCompat.getX(ev, activePointerIndex);
final int totalDelta = (int) (x - mInitialMotionX);
int nextPage = determineTargetPage(currentPage, pageOffset, initialVelocity,
totalDelta);
setCurrentItemInternal(nextPage, true, true, initialVelocity);
//add by jcodecraeer
if(mFollowViewPager!=null){
mFollowViewPager.setCurrentItemInternal(nextPage, true, true, initialVelocity);
}
mActivePointerId = INVALID_POINTER;
endDrag();
needsInvalidate = mLeftEdge.onRelease() | mRightEdge.onRelease();
}

至此,我们完成了所有的修改,其实也没改几行。

那么在activity中如何使用改造后的ViewPager让两个ViewPager联动呢?假设有一个是mViewPager,有一个是mFollowViewPager,我想让mFollowViewPager随着mViewPager动,则:
mPager.setFollowViewPager(mFollowViewPager);

需要注意的是在我接下来给出的demo中,我屏蔽了followViewPager的所有触摸事件,让主ViewPager覆盖在followViewPager之上,这跟我要实现的效果稳合的。如果你要让followViewPager也能反过来使主ViewPager也能跟着移动不妨反过来调用:
mFollowViewPager.setFollowViewPager(mPager);

但是我不确定这种双向调用是否会出现问题,因为我并没有很严格的考虑从mFollowViewPager变量在移动过后本应该导致的一些状态变化(比如相关的变量)。
我要举报
如以上问答信息为低俗、色情、不良、暴力、侵权、涉及违法等信息,可以点下面链接进行举报!
大家都在看
有没有自制冰晶的冷风扇
把,我很喜欢旅游,因为旅游可以让我放松,翻
凌派摩卡金是什么颜色
禅与净土可以一起修吗??是否更有利于往生
投五只最高价与最低价的股票,哪个赚得多
怀化市工商行政管理学会地址在哪,我要去那里
Itisobviousthatithasbeentoolatetotakeactio
张杰 罗志祥 林俊杰 胡彦斌 棒棒堂 SJ上过以
戏曲词什么样的什么是什么样的唱得很快的
落雁泓整首诗带拼音的
明天要去湖口县九钢铜厂出差,我11:30到达庐山
读下图,完成下列各题。【小题1】从图中岩层
检测二氧化碳传感器和检测酒精传感器的电路能
冬冬平价百货超市地址在什么地方,想过去办事
奥克特珐玛人血白蛋白怎么样
推荐资讯
电子手表当中的AL 和DL是什么意思
天津寿衣店这个地址在什么地方,我要处理点事
宗申弯梁发动机放机油的螺丝旁边一个小一些的
宝骏730怎么样?
乔迁那天女主人应该穿什么衣服
蛮耗收费站地址在什么地方,想过去办事
天河区天河公园附近哪里租房便宜?
总是感觉眼里有泪有层膜,看不清是什么情况
你知道猎人小屋的猎人日记在哪吗?
我红酒喝多了,有什么好的方法快速解酒!
给残,歉,霉换部首组新字并组词(组三组)
即已容颜动天下 何必开口乱芳华 什么意思 出
正方形一边上任一点到这个正方形两条对角线的
阴历怎么看 ?