Android中常常也會(huì)出現(xiàn)像Web網(wǎng)頁上圖片輪播的效果货岭,也就是實(shí)現(xiàn)圖片的循環(huán)滾動(dòng),這里以LoopingViewPager為例,講解一下如何實(shí)現(xiàn)viewPager的無限滾動(dòng)闰集。
LoopingViewPager原理講解
這里主要有兩個(gè)類LoopPagerAdapterWrapper和LoopViewPager俗壹。主要的思想簡單來說就是存在兩個(gè)數(shù)據(jù)源科汗,外面的數(shù)據(jù)源就是我們看到的數(shù)據(jù)項(xiàng),內(nèi)部的數(shù)據(jù)源绷雏,需要在開頭和末尾各添加1個(gè)數(shù)據(jù)項(xiàng)(以A头滔、B表示),這樣相比外部的count多兩項(xiàng)涎显,A顯示的內(nèi)容跟真實(shí)數(shù)據(jù)源最后一項(xiàng)相同坤检,B顯示的內(nèi)容跟真實(shí)數(shù)據(jù)源第一項(xiàng)相同。
- LoopPagerAdapterWrapper
通過繼承PagerAdapter期吓,實(shí)現(xiàn)PagerAdapter的功能早歇,內(nèi)部引用了一個(gè)新的pagerAdpater,實(shí)現(xiàn)了一個(gè)新的數(shù)據(jù)源的映射讨勤。映射的規(guī)則是這樣的:
原始的數(shù)據(jù)源[0,1,2,3]箭跳,對(duì)應(yīng)內(nèi)部的數(shù)據(jù)源則是[0,1,2,3,4,5],換算的公式則是潭千,realPosition=(position-1)%count 對(duì)應(yīng)的關(guān)系:[0->3, 1->0, 2->1, 3->2, 4->3, 5->0]谱姓。這樣,內(nèi)部的數(shù)據(jù)源在調(diào)用instantiateItem的時(shí)候刨晴,則會(huì)在生成對(duì)應(yīng)的View的時(shí)候屉来,調(diào)用對(duì)應(yīng)realPostion位置上的View,具體的代碼如下:
int toRealPosition(int position) {
int realCount = getRealCount();
if (realCount == 0)
return 0;
int realPosition = (position-1) % realCount;
if (realPosition < 0)
realPosition += realCount;
return realPosition;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
int realPosition = (mAdapter instanceof FragmentPagerAdapter || mAdapter instanceof FragmentStatePagerAdapter)
? position
: toRealPosition(position);
if (mBoundaryCaching) {
ToDestroy toDestroy = mToDestroy.get(position);
if (toDestroy != null) {
mToDestroy.remove(position);
return toDestroy.object;
}
}
return mAdapter.instantiateItem(container, realPosition);
}
上面的代碼解決了正常情況下狈癞,在邊界條件下茄靠,viewpager可以滑動(dòng)的問題(添加了兩個(gè)邊界的pagerItem的顯示),但是會(huì)有一個(gè)新的問題產(chǎn)生亿驾,就是當(dāng)我滑動(dòng)到這兩個(gè)新添加的pagerItem的時(shí)候嘹黔,是如何可以滑動(dòng)的。
- LoopViewPager
通過繼承Viewpager,并設(shè)置了一個(gè)內(nèi)部的PagechangeListener莫瞬,在onPageScrolled的回調(diào)中儡蔓,發(fā)現(xiàn)當(dāng)內(nèi)部的pagerAdpater的position滑動(dòng)到邊界的時(shí)候,通過調(diào)用setCurrentItem疼邀,將position又設(shè)置到正確的位置喂江。具體代碼如下:
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
int realPosition = position;
if (mAdapter != null) {
realPosition = mAdapter.toRealPosition(position);
if (positionOffset == 0
&& mPreviousOffset == 0
&& (position == 0 || position == mAdapter.getCount() - 1)) {
setCurrentItem(realPosition, false);
}
}
mPreviousOffset = positionOffset;
if (mOuterPageChangeListener != null) {
if (realPosition != mAdapter.getRealCount() - 1) {
mOuterPageChangeListener.onPageScrolled(realPosition,
positionOffset, positionOffsetPixels);
} else {
if (positionOffset > .5) {
mOuterPageChangeListener.onPageScrolled(0, 0, 0);
} else {
mOuterPageChangeListener.onPageScrolled(realPosition,
0, 0);
}
}
}
}
綜上,可以看出這是個(gè)比較簡單的方案了旁振,唯一不足的地方就是需要監(jiān)聽pageChangeListener的pageScroll方法获询,重新設(shè)置position的值(具體的方法是調(diào)用scrollTo進(jìn)行重繪一遍涨岁,比較浪費(fèi)性能)。
進(jìn)階實(shí)現(xiàn)自動(dòng)滾動(dòng)的功能
因?yàn)閂iewpager已經(jīng)自帶了smoothScroll的功能吉嚣,則我們只需要在固定的間隔時(shí)間發(fā)送一個(gè)讓viewPager滾動(dòng)的message即可梢薪,這個(gè)還是比較簡單而且容易實(shí)現(xiàn)的。
PS:轉(zhuǎn)載請(qǐng)注明來自原文鏈接尝哆。