一個簡單的廣告輪播庫-SimpleBanner

效果演示

banner

上圖這個效果你可以于淘寶,愛奇藝,華為應用商店等一系列熱門或者不熱門的APP中看到,因為使用Banner可以通過固定大小的位置動態或者靜態的向用戶展示多條甚至幾十條(雖然沒人這樣子做)圖文數據,對于我自己來說也經常會使用到Banner來展示廣告數據或者手機啟動引導界面,所以就有了現在這個SimpleBanner庫,它肯定不是最完美的,但是我希望它是有用的。

使用

  1. 在你project的build.gradlerepositories里面添加:
allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }```
2. 在你所需的module的```build.gradle```里面添加依賴:

dependencies {
compile 'com.github.AmatorLee:SimpleBanner:1.0.0'
}```

  1. 在你需要展示Banner數據的xml文件中引入:
  <com.amator.simplebanner.widget.SimpleBanner
        android:id="@+id/banner_simple"
        android:layout_width="match_parent"
        android:layout_height="200dp">
    </com.amator.simplebanner.widget.SimpleBanner>```
4. 在Activity或者Fragment中配置SimpleBanner:

/**
* 測試本地圖片資源,圖片較大,造成開銷大
/
private int[] imaRes = {R.drawable.a123, R.drawable.color, R.drawable.flash, R.drawable.zhixiao, R.drawable.xiaozhi};
private SimpleBanner mBanner;
/
*
* 默認圖片資源(圖片URL地址)
/
private String[] defaultUrl = new String[]{
"http://g.hiphotos.baidu.com/imgad/pic/item/a8773912b31bb051be533b24317adab44aede043.jpg",
"http://g.hiphotos.baidu.com/imgad/pic/item/c75c10385343fbf22c362d2fb77eca8065388fa0.jpg",
"http://liaoning.sinaimg.cn/2014/1111/U10435P1195DT20141111220802.jpg",
"http://photocdn.sohu.com/20151124/mp43786429_1448294862260_4.jpeg",
"http://h.hiphotos.baidu.com/image/pic/item/faedab64034f78f0b00507c97e310a55b3191cf9.jpg"};
/
*
* 測試文字提示
*/
private String[] titleRes = {"深色", "淺色", "動物", "宋智孝", "宋智孝"};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //加載本地圖片
    List<Integer> mDatas = new ArrayList<>();
    for (int i = 0; i < imaRes.length; i++) {
        mDatas.add(imaRes[i]);
    }
    //加載網絡圖片
    List<String> mImageRes = new ArrayList<>();
    for (int i = 0; i < defaultUrl.length; i++) {
        mImageRes.add(defaultUrl[i]);
    }
    List<String> tips = new ArrayList<>();
    for (int i = 0; i < titleRes.length; i++) {
        tips.add(titleRes[i]);
    }
    //1.寫在布局文件中
    mBanner = (SimpleBanner) findViewById(R.id.banner_simple);
    mBanner.setImageRes(mImageRes)
            .start();//調用則表示允許自動循環播放
    //2.代碼中直接使用
    LinearLayout linearLayout = (LinearLayout) findViewById(R.id.ll_banner_container);
    mBanner = SimpleBanner.createBanner(this)
            .setImageRes(mImageRes);
    mBanner.start();
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtil.dp2px(this, 200));
    linearLayout.addView(mBanner, params);

}
@Override
protected void onPause() {
    super.onPause();
    //釋放資源避免內存泄漏
    mBanner.stop();
}```

就這樣就可以實現以下效果

simplebanner

可能有人會問,那么切換效果呢?,其實切換效果的實現很簡單,但是實現炫酷的切換效果需要大量是時間進行計算,同時對于部分APP來說是不合適的,所以我不打算提供多種切換效果,當然你可以自己實現然后調用setBannerPageTranFormer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer)即可。同時我推薦一個開源庫android-viewpager-transformers,感謝。

代碼分析

短短的使用步驟絞盡腦汁也寫不出來,所以直接show you the fuck codes就好。

在此之前我先簡單來說說SimpleBanner實現無限輪播的實現方式
現今gayhub上的banner開源庫主要分為兩大類:

  1. 使用ViewPager實現
  2. 自定義或者使用RecyclerView等實現

那么Simple是使用第一種方式,所以就結合代碼分析來說說第一種的套路吧:
既然知道了精髓是ViewPager,在確定ViewPager之后我們要考慮以下兩個問題

  1. 實現循環播放
  2. 如何進行自動循環
回答一

其實實現循環很簡單,只要在最后一張圖片滑動時把它下一張重新設置為第一張就可以實現“偽循環”,但是這樣重新滑進去會造成很不好的用戶體驗,所以我們給ViewPager的adapter設置一個很大的數,返回一個巨大的數值,通過與實際數量的求余就可以實現“無限循環”。

回答二

很多時候我們都會新建一個Handler,然后再其實現方法里面對viewPager進行setCurrentItem,然后再界面跳轉完成后掩飾某個delayTime不斷發送自身空消息就可以實現自動播放了,bug,還有更好的辦法嗎?知道我看到了達哥的《手把手教你用ViewPager自定義實現Banner輪播 》,找到了更好的寫法,當然思想是一樣的。
BannerViewPager

/**
 * Created by AmatorLee on 2017/7/21.
 */

public class BannerViewPager extends ViewPager {

    private int delayTime = 3000;//設置展示時間
    private BannerDirection mBannerDirection = LEFT;//試著輪播方向
    private boolean isAuto = true;//是否為自動輪播

    public void setAuto(boolean auto) {
        isAuto = auto;
    }


    public void setDelayTime(int delayTime) {
        this.delayTime = delayTime;
    }

    public void setBannerDirection(BannerDirection bannerDirection) {
        mBannerDirection = bannerDirection;
    }

    public BannerViewPager(Context context) {
        super(context);
    }

    public BannerViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    public void start() {
        if (isAuto) {
            //每次開始前先remove掉避免重復調用
            removeCallbacks(mBannerTask);
            postDelayed(mBannerTask, delayTime);
        }
    }

    public void stop() {
        removeCallbacks(mBannerTask);
    }


    private Runnable mBannerTask = new Runnable() {
        @Override
        public void run() {
            bannerPlay();
        }
    };

    private void bannerPlay() {
        PagerAdapter adapter = getAdapter();
        if (adapter != null) {
            int count = adapter.getCount();
            int currentItem = getCurrentItem();
            switch (mBannerDirection) {
                case LEFT:
                    currentItem++;
                    if (currentItem >= count) {
                        currentItem = 0;
                    }
                    break;
                case RIGHT:
                    currentItem--;
                    if (currentItem < 0) {
                        currentItem = count - 1;
                    }
                    break;
            }
            setCurrentItem(currentItem);
        }
        start();
    }

    @Override
    protected void onDetachedFromWindow() {
        removeCallbacks(mBannerTask);
        super.onDetachedFromWindow();
    }

}```
如上所說,需要給Adapter設置一個很大的數```Integer.MAX_VALUE```
**BannerViewPager**

/**

  • Created by AmatorLee on 2017/7/20.
    */

public class BannerAdapter extends PagerAdapter {

private List<View> mViews;
public static final String TAG = "BannerPagerAdapter";
private OnBannerClickListener mBannerClickListener;
private int pos;

public void setBannerClickListener(OnBannerClickListener bannerClickListener) {
    mBannerClickListener = bannerClickListener;
}

public BannerAdapter(List<View> mViews) {
    this.mViews = mViews;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
    if (mViews == null || mViews.size() == 0) {
        Log.d(TAG, "instantiateItem return");
        return null;
    }
    final int pos = position % mViews.size();
    View view = mViews.get(pos);
    ViewGroup parent = (ViewGroup) view.getParent();
    if (parent != null) {
        parent.removeView(view);
    }
    view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.d(TAG, "instantiateItem pos is :" + pos);
            if (mBannerClickListener != null) {
                mBannerClickListener.onBannerClick(pos);
            }
        }
    });
    container.addView(view);
    return view;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    if (mViews == null || mViews.size() == 0) {
        return;
    }
    int pos = position % mViews.size();
    Log.d(TAG, "destroyItempos: " + pos);
    container.removeView(mViews.get(pos));
}

@Override
public int getCount() {
    return mViews == null ? 0 : Integer.MAX_VALUE;
}

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


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

}其實看到上面的演示圖還有最后一個注意點就是指示器Indicator,我嘗試過自己自定義幾種類型的BannerIndicator```,但是這樣做的話實現太多的子類,所以我采取代碼家AndroidImageSlider的寫法使用圖層Drawable動態實現。

總結

Banner幾乎是最常見的一種效果同時對于我們Coder來說也應該是最容易實現的,所以自己抽空寫一下。如果發現有什么錯漏的地方,麻煩指出,同時我也會不斷自我完善。
gayhub地址:SimpleBanner

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374

推薦閱讀更多精彩內容