打造一個簡單實用的安卓廣告欄控件

思路

循環(huán) ViewPager 的兩種實現(xiàn)方法這篇文章中介紹了廣告欄的兩種實現(xiàn)思路,但是直接用到項目中還是會有不少問題。

  • 方法1:將 count 設(shè)為無限大,制造一種假的循環(huán)
    這種方法在實際的項目中容易導(dǎo)致anr勃救,在調(diào)用setCurrentItem或者在數(shù)據(jù)集發(fā)生改變時調(diào)用notifyDataSetChanged時有發(fā)生宏榕。
  • 方法2:在 ViewPager 的首尾添加一個重復(fù)的 View
    這種做法的問題是每循環(huán)一次會額外的多調(diào)用一次setCurrentItem,性能不佳碱鳞,尤其是用戶快速滾動時表現(xiàn)不夠流暢桑李。

能否將兩種方法結(jié)合起來呢,比如我將count設(shè)為200個窿给,每次滑動到最后一頁或者第一頁的時候再執(zhí)行setCurrentItem(middleItem)贵白。當然,我還需要對滑出去的View做好回收崩泡,這點仿照ListView去做即可禁荒。

說干就干。

實現(xiàn)我們的PagerAdapter

看碼說話

public abstract class CyclePagerAdapter extends PagerAdapter {

    private final int MAX_PAGES = 200;
    // 對View做緩存角撞,防止每次都去inflate
    protected LinkedList<View> mScrapViews = new LinkedList<View>();
    // 最多緩存兩個View
    protected int mMaxScrapViewSize = 2;

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        View scrap = retrieveFromScrap();
        View view = getView(position, scrap, container);
        container.addView(view);
        return view;
    }

    private View retrieveFromScrap() {
        if (mScrapViews.size() > 0) {
            return mScrapViews.removeLast();
        }
        return null;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        View view = (View) object;
        container.removeView(view);
        if (mScrapViews.size() < mMaxScrapViewSize) {
            mScrapViews.add(view);
        }
    }
    // 返回 getRealCount 的整數(shù)倍呛伴,該數(shù)最大值為 MAX_PAGES,這里將MAX_PAGES設(shè)為200谒所。
    @Override
    public int getCount() {
        if (getRealCount() < 2) {
            return getRealCount();
        }
        return getRealCount() * (MAX_PAGES / getRealCount());
    }

    public View getView(int position, View convertView, ViewGroup container) {
        int realPosition = getRealPosition(position);
        return getViewAtRealPosition(realPosition, convertView, container);
    }

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

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

    public int getRealPosition(int position) {
        if (getRealCount() == 0) {
            return 0;
        }
        return position % getRealCount();
    }

    public abstract int getRealCount();

    public abstract View getViewAtRealPosition(int position, View convertView, ViewGroup container);

}

在CyclePagerAdapter中热康,getCount返回值最大為200,并且該數(shù)是getRealCount的整數(shù)倍劣领。這里我們還添加了一個回收機制姐军,防止多次創(chuàng)建View導(dǎo)致性能損耗。

使用時只需要繼承CyclePagerAdapter即可。

public class SimpleBannerAdapter extends CyclePagerAdapter {

        private static final int[] drawableIds = new int[]{R.drawable.desert, R.drawable.koala,
                R.drawable.jellyfish, R.drawable.hydrangeas};
        private Context mContext;

        public SimpleBannerAdapter(Context context) {
            this.mContext = context;
        }

        @Override
        public int getRealCount() {
            return drawableIds.length;
        }

        @Override
        public View getViewAtRealPosition(final int position, View convertView, ViewGroup container) {
            if (convertView == null) {
                convertView = LayoutInflater.from(mContext).inflate(R.layout.banner_item, container, false);
            }
            ImageView imageView = (ImageView) convertView.findViewById(R.id.imageView);
            imageView.setImageResource(drawableIds[position]);
            return convertView;
        }
    }

監(jiān)聽ViewPager滾動

public class CycleViewPager extends ViewPager {
    private CyclePagerAdapter mCyclePagerAdapter;
    @Override
    public void setAdapter(PagerAdapter adapter) {
        super.setAdapter(adapter);
        if (adapter instanceof CyclePagerAdapter) {
            mCyclePagerAdapter = (CyclePagerAdapter) adapter;
            addOnPageChangeListener(mOnPageChangeListener);
            setMiddleItemInner(false, true);
        }
    }
    private OnPageChangeListener mOnPageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float offset, int offsetPixels) {
            if (offset != 0) {
                return;
            }
            if (mCyclePagerAdapter == null || mCyclePagerAdapter.getRealCount() <= 1) {
                return;
            }
            // 第一頁
            if (position == 0) {
                setMiddleItemInner(false, false);
                //最后一頁
            } else if (position == mCyclePagerAdapter.getCount() - 1) {
                setMiddleItemInner(false, false);
            }
        }

        @Override
        public void onPageSelected(int position) {
           
        }

    };
    // 設(shè)置到中間的item奕锌。當ViewPager滾動到第一頁或者最后一頁的時候調(diào)用著觉。
    public void setMiddleItem() {
        setMiddleItemInner(true, true);
    }

    private void setMiddleItemInner(boolean setToFirstItem, boolean immediately) {
        if (mCyclePagerAdapter != null && mCyclePagerAdapter.getRealCount() > 1) {
            int currentItem = setToFirstItem ? 0 : getCurrentItem();
            final int middleItem = mCyclePagerAdapter.getCount() / 2 + mCyclePagerAdapter.getRealPosition(currentItem);
            if (immediately) {
                setCurrentItem(middleItem, false);
            } else {
                post(new Runnable() {
                    @Override
                    public void run() {
                        setCurrentItem(middleItem, false);
                    }
                });
            }
        }
    }
}

至此,我們已經(jīng)實現(xiàn)了一個可以循環(huán)滾動的ViewPager了歇攻,當然固惯,自動滾動以及ViewPager指示器我們都還沒有實現(xiàn),如果想了解這部分可以參考我的github缴守。我已經(jīng)將這個項目上傳到 https://github.com/leandom/CycleViewPager 這里了葬毫。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市屡穗,隨后出現(xiàn)的幾起案子贴捡,更是在濱河造成了極大的恐慌,老刑警劉巖村砂,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烂斋,死亡現(xiàn)場離奇詭異,居然都是意外死亡础废,警方通過查閱死者的電腦和手機汛骂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來评腺,“玉大人帘瞭,你說我怎么就攤上這事≥锛ィ” “怎么了蝶念?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長芋绸。 經(jīng)常有香客問我媒殉,道長,這世上最難降的妖魔是什么摔敛? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任廷蓉,我火速辦了婚禮,結(jié)果婚禮上舷夺,老公的妹妹穿的比我還像新娘苦酱。我一直安慰自己,他們只是感情好给猾,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布疫萤。 她就那樣靜靜地躺著,像睡著了一般敢伸。 火紅的嫁衣襯著肌膚如雪扯饶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音尾序,去河邊找鬼钓丰。 笑死,一個胖子當著我的面吹牛每币,可吹牛的內(nèi)容都是我干的携丁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼兰怠,長吁一口氣:“原來是場噩夢啊……” “哼梦鉴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起揭保,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤肥橙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后秸侣,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體存筏,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年味榛,在試婚紗的時候發(fā)現(xiàn)自己被綠了椭坚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡搏色,死狀恐怖藕溅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情继榆,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布汁掠,位于F島的核電站略吨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏考阱。R本人自食惡果不足惜翠忠,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乞榨。 院中可真熱鬧秽之,春花似錦、人聲如沸吃既。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鹦倚。三九已至河质,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掀鹅。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工散休, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人乐尊。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓戚丸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親扔嵌。 傳聞我的和親對象是個殘疾皇子限府,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,072評論 25 707
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法对人,內(nèi)部類的語法谣殊,繼承相關(guān)的語法,異常的語法牺弄,線程的語...
    子非魚_t_閱讀 31,622評論 18 399
  • 第一姻几,抵御誘惑 誘惑來自生活中的各種打擾,來自網(wǎng)絡(luò)势告、手機和各種外在影響蛇捌,來自內(nèi)心抵御這些干擾帶來的心力損耗。 首先...
    withinsky閱讀 210評論 0 0
  • 你相信愛情嗎咱台?無論你是否受過傷络拌,你都一直堅持地相信下去。有答案嗎回溺?我不知道春贸,其實答案只是我們內(nèi)心對自己一段歲月的結(jié)...
    噗梅閱讀 111評論 0 0
  • 當洛風(fēng)回望自己多年以前的自己,記憶便一下子泄開了口子遗遵,帶著不可阻擋的勢萍恕,席卷了已經(jīng)注釋好整個人生的綴角。 該怎么描...
    松風(fēng)山月閱讀 623評論 0 1