Android - ViewPager進階篇之無限滑動

在Android開發(fā)中牵囤,我們常常用ViewPager來為自己的應用創(chuàng)建廣告條幅沦泌,并且常常會遇到這樣的需求 —— ViewPager無限滑動烙常。

其實荆永,仔細想一下原理還是挺簡單的。無非是當我們滑動到最后一頁般渡,再向后滑動時定位到第一頁;當我們滑動到第一頁懒豹,再向前滑動時定位到最后一頁。

但是驯用,相信很多朋友都遇到過這個問題 - 視圖的過度效果不自然脸秽。

小編也是通過百度和谷歌查找了很多解決方案,實驗了很多方法蝴乔,總結(jié)了一個相對不錯的方法记餐,接下來給各位分享下滑動效果、實現(xiàn)細節(jié)以及一些踩過的坑薇正。

1.無限滑動效果(左右無限滑動)

事先準備好2張滑動圖片(有想試驗的小伙伴片酝,自備圖片啊,小編就不提供了...)

png_image1.png

運行效果圖(左右無限循環(huán)):

  • 為了顯示更加直觀挖腰,小編僅用了2張圖片雕沿。
gif_my_viewpage.gif

2.代碼實現(xiàn)

(1) Activity的Xml布局文件(非常簡單的布局)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v4.view.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="200dp"/>
</RelativeLayout>

(2)Activity

public class MainActivity extends AppCompatActivity {

    private ViewPager mViewPager;
    private ViewPagerAdapter mAdapter;
    private int[] images; // 圖片資源數(shù)組

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView(); // 初始化視圖
        initData(); // 初始化數(shù)據(jù)
    }

    /**
     * 初始化視圖
     */
    private void initView() {
        mViewPager = (ViewPager) findViewById(R.id.view_pager);
    }

    /**
     * 初始化數(shù)據(jù)
     */
    private void initData() {
        images = new int[]{R.mipmap.image1, R.mipmap.image2};
        mAdapter = new ViewPagerAdapter(this, images);
        mViewPager.setAdapter(mAdapter);

        // 將ViewPager定位到中間頁(Short.MAX_VALUE/2附近的圖片資源數(shù)組第1個元素對應的頁面)
        // 目的:1.圖片個數(shù) >1 才輪播    2.定位到中間頁,向左向右都可滑
        if(images.length > 1) {
            mViewPager.setCurrentItem(((Short.MAX_VALUE / 2) / images.length) * images.length, false);
        }
    }
}

(3)ViewPagerAdapter

/**
 * @ClassName: ViewPagerAdapter
 * @Description: ViewPager適配器
 * @Author Wangnan
 * @Date 2016/9/1
 */
public class ViewPagerAdapter extends PagerAdapter{
    
    private Context mContext;
    private int[] mImages; // 圖片資源ID數(shù)組
    private List<ImageView> mImageViews; // ImageView集合

    public ViewPagerAdapter(Context context, int[] images){
        mContext = context;
        mImages = images;
        mImageViews = new ArrayList<>();
        initImageViews(mImages);
    }

    /**
     * 初始化ImageViews集合
     * @param imageIds
     */
    private void initImageViews(int[] imageIds) {

        // 根據(jù)圖片資源數(shù)組填充ImageViews集合
        for(int i = 0 ; i < imageIds.length ; i++){
            ImageView mImageView = new ImageView(mContext);
            mImageView.setImageResource(imageIds[i]);
            mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            mImageViews.add(mImageView);
        }

        // ImageViews集合中的圖片個數(shù)在[2,3]時會存在問題猴仑,遞歸再次填充一遍
        if(mImageViews.size() > 1 && mImageViews.size() < 4){
            initImageViews(imageIds);
        }
    }

    @Override
    public int getCount() {
        return mImageViews.size() <=1 ? mImageViews.size() : Short.MAX_VALUE;
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        ImageView mImageView = mImageViews.get(position % mImageViews.size());
        container.addView(mImageView);
        return mImageView;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View)object);
    }
}

具體需要解釋的地方审轮,代碼中都做了相應的注釋,就不再多做解釋了,但后面小編還會解釋遇到的兩個坑點疾渣。

3.細節(jié)踩坑

相信在看小編的實現(xiàn)方式之前篡诽,有人在網(wǎng)上也找到了很多相似的實現(xiàn)。小編接下來要講的就是 —— 對“這些相似的實現(xiàn)”踩一下坑榴捡。

1. 出現(xiàn)異常:java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

原因:圖片資源少于4個杈女,對應生成的ImageView也少于4個。

眾所周知薄疚,ViewPager一般會維護2~3個頁,如果只有3個ImageView,很可能出現(xiàn)這種情況赊琳,在生成完3個Page頁后并準備生成第4個頁面時街夭,本應該移除的最前面的頁面還未被移除,系統(tǒng)就會報異常并且給你這樣一個提示:You must call removeView() on the child's parent first(意思是讓你先將最前面頁的子View從最前面頁移除掉躏筏,再將該子View添加到第4頁中)板丽。

解決辦法:在只有1張圖片時,不能滑動趁尼,暫不處理埃碱;如果有2~3張圖片時,遞歸增加至大于等于4個ImageView為止(下方為小編解決該問題的代碼)酥泞。

    /**
     * 初始化ImageViews集合
     * @param imageIds
     */
    private void initImageViews(int[] imageIds) {

        ......

        // ImageViews集合中的圖片個數(shù)在[2,3]時會存在問題砚殿,遞歸再次填充一遍
        if(mImageViews.size() > 1 && mImageViews.size() < 4){
            initImageViews(imageIds);
        }
    }

2. 滑動效果出現(xiàn)混亂(后面會附上混亂的效果圖)

原因:ViewPager源碼本身存在問題 - 數(shù)據(jù)范圍越界問題。

小編的獲取ViewPager頁面數(shù)量的方法是這樣寫的:

    @Override
    public int getCount() {
        return mImageViews.size() <=1 ? mImageViews.size() : Short.MAX_VALUE;
    }
  • 小于1時芝囤,頁面沒有滑動似炎,不需要擴充頁面數(shù)量;
  • 大于1時悯姊,取Short取值范圍的最大值32767(我們會有3W多頁面羡藐,但不會同時存在,因為ViewPager最多維持3個頁面)

小編這里用的是Short悯许,但一開始從網(wǎng)上找的相似實現(xiàn)全是使用的Integer(Integer.MAX_VALUE = 2147483647, 也就是我們的ViewPager將會有大概21億個頁面)仆嗦,如果使用Integer,比較細心的朋友會發(fā)現(xiàn)滑動經(jīng)常出現(xiàn)混亂先壕。

頁面反向回彈Bug

gif_my_erroe.gif

我們松手時瘩扼,頁面出現(xiàn)反向回彈(1~2頁),這和我們期望的滑動效果不一致垃僚。

這是其中一種Bug邢隧,還有一些不太好說明的滑動Bug,小編就用“滑動混亂”這個名詞進行解釋了...

解決辦法:減少ViewPager頁面的數(shù)量(小編使用的Short代替Integer減少了頁面數(shù)量)冈在。

具體的無Bug的臨界值倒慧,有興趣的小伙伴可以去實驗,小編的測試結(jié)果如下:

  • 800萬以內(nèi):基本無滑動Bug;

  • 1000萬左右:開始出現(xiàn)當前頁面定位不準確的Bug,但還未出現(xiàn)反向回彈Bug。(小編到這就已經(jīng)忍不了了.../(ㄒoㄒ)/~~纫谅,已經(jīng)不打算再往下測了...)

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末炫贤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子付秕,更是在濱河造成了極大的恐慌兰珍,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件询吴,死亡現(xiàn)場離奇詭異掠河,居然都是意外死亡,警方通過查閱死者的電腦和手機猛计,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門唠摹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人奉瘤,你說我怎么就攤上這事勾拉。” “怎么了盗温?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵藕赞,是天一觀的道長。 經(jīng)常有香客問我卖局,道長斧蜕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任砚偶,我火速辦了婚禮惩激,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蟹演。我一直安慰自己风钻,他們只是感情好,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布酒请。 她就那樣靜靜地躺著骡技,像睡著了一般。 火紅的嫁衣襯著肌膚如雪羞反。 梳的紋絲不亂的頭發(fā)上布朦,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機與錄音昼窗,去河邊找鬼是趴。 笑死,一個胖子當著我的面吹牛澄惊,可吹牛的內(nèi)容都是我干的唆途。 我是一名探鬼主播富雅,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼肛搬!你這毒婦竟也來了没佑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤温赔,失蹤者是張志新(化名)和其女友劉穎蛤奢,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體陶贼,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡啤贩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了拜秧。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痹屹。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖腹纳,靈堂內(nèi)的尸體忽然破棺而出痢掠,到底是詐尸還是另有隱情驱犹,我是刑警寧澤嘲恍,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站雄驹,受9級特大地震影響佃牛,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜医舆,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一俘侠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蔬将,春花似錦爷速、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至毙石,卻和暖如春廉沮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背徐矩。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工滞时, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人滤灯。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓坪稽,卻偏偏與公主長得像曼玩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子刽漂,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容