问题产生背景
在使用ViewPager实现无限轮播效果时,为了达到无缝对接的效果,我在ViewPager的最左侧(position = 0)与左右侧(position = getCount() + 1)的位置新增了两个页卡用来对应映射尾页 / 首页的页卡图片,设计效果如下:
设计好对应的映射item效果后,我在ViewPager的onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
方法中对ViewPager的滑动进行了监听并通过setCurrentItem(int item, boolean smoothScroll)
方法进行首页 / 尾页切换从而达到无限轮播的效果,具体代码如下:
/**
* 页卡滚动状态回调
* @param position 页卡位置 position=0,开始边界;position=getCount()-1,结束边界。
* @param positionOffset 是当前页面滑动比例,如果页面向右翻动,这个值不断变大,
* 最后在趋近1的情况后突变为0。如果页面向左翻动,这个值不断变小,最后变为0
* @param positionOffsetPixels 当前页面偏移的像素位置.
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (isAutoLoop && positionOffset == 0) {// 允许无限轮播且滚动完成进入内部判断
if (position == 0) {// 如果position为0,则跳转至结束位置
// switch to the last page.
setCurrentItem(pagerAdapter.getRealPageEndPos(), false);
}
if (position == pagerAdapter.getCount() - 1) {// 如果position为pagerAdapter.getCount() - 1,则跳转至开始位置
// switch to the first page.
setCurrentItem(pagerAdapter.getRealPageStartPos(), false);
}
}
}
这里我也对ViewPager切换过程中可能存在的问题进行了预防,参考【Android寻坑之路】解决ViewPager使用setCurrentItem跨距离(中间间隔多个page页)切换过渡动画闪现问题
运行后发现出现了在最左侧 / 右侧滑动切换时出现了闪屏(白屏)的现象,具体如下图(实际问题比图片更突出,左右侧滑动都会闪屏):
写在前面的解决方式
在onPageScrollStateChanged(int state)方法中来进行轮播效果的控制
@Override
public void onPageScrollStateChanged(int state) {
// 这里主要是解决在onPageScrolled出现的闪屏问题
// (positionOffset为0的时候,并不一定是切换完成,所以动画还在执行,强制再次切换,就会闪屏)
switch (state) {
case ViewPager.SCROLL_STATE_IDLE:// 空闲状态,没有任何滚动正在进行(表明完成滚动)
if (isAutoLoop) {
if (getCurrentItem() == 0) {
setCurrentItem(pagerAdapter.getRealPageEndPos(), false);
} else if (getCurrentItem() == pagerAdapter.getCount() - 1) {
setCurrentItem(pagerAdapter.getRealPageStartPos(), false);
}
}
break;
case ViewPager.SCROLL_STATE_DRAGGING:// 正在拖动page状态
break;
case ViewPager.SCROLL_STATE_SETTLING:// 手指已离开屏幕,自动完成剩余的动画效果
break;
}
}
问题分析
再次请出结构图:
这里我们先假设真实的C页面(position = 3)位C1,最左侧(position = 0)的黄色C页面为C2,,导致问题出现的步骤如下:
在ViewPager的A页面(默认显示A页)右滑来切换至左侧的C2页(这个C2只是作为映射起到无缝对接的作用),当C2页切换出来后会快速在onPageScrolled
方法中快速触发setCurrentItem
方法跳转C1页。然而由于C2的动画未完成就开始切换至C1(这个是与onPageScrolled
方法的调用时机有关),而切换至C1过程是无动画的,所以C2的动画还没彻底结束就直接切到了C1,由于滚动时机不对影响了无缝对接的效果造成了闪屏的现象(C2动画未完成,立即切换至C1,因为C2还在进行中而C1已经instantiateItem
出来,那么C2页面就会被迅速回收,导致了闪屏的现象)。
解决后的效果:
关于OnPageChangeListener解析,请参考下文:
ViewPager的addOnPageChangeListener方法详解
如果您有更好的解决方案欢迎评论分享,如有错误,请批评指正,谢谢。