Android App Banner,用它就夠了脏榆。無限輪播猖毫、簡單易用、擴(kuò)展性強(qiáng)的BannerView

按照慣例先上效果圖:

引導(dǎo)頁效果

標(biāo)題等信息跟隨頁面滾動

標(biāo)題固定须喂,圓點指示器

標(biāo)題固定吁断,數(shù)字指示器

還有各種效果

體驗Demo

點擊下載或掃碼下載DemoApk

"掃碼下載"

寫在前面

GitHub上有更加詳細(xì)的使用介紹的,如果你想直接看GitHub上的也可以直接點擊后面的傳送門去往GitHub坞生。我是傳送門

本文的內(nèi)容可能有點長仔役,如果你想要直接但Demo的源碼的,可以直接跳到最后是己,最后有完整的代碼(包括Java代碼和XML代碼)又兵。

前言

今天給大家推薦一款支持無限輪播的,簡單易用卒废、擴(kuò)展性強(qiáng)且超級穩(wěn)定的輪播圖庫沛厨。

·為什么說簡單易用?答:因為實現(xiàn)起來比較簡單摔认,兩行代碼就可以輕松實現(xiàn)逆皮。

//找到控件。
BannerView bannerView = findViewById(R.id.vp_banner_view);
//設(shè)置數(shù)據(jù)源并啟動輪播参袱。
bannerView.setEntries(entries, true);

·為什么說擴(kuò)展性強(qiáng)电谣?答:布局樣式完全由自己決定,想怎么布局就怎么布局抹蚀,我的原則是你的布局你做主剿牺。如果你需要指示器你可以使用我提供的圓點型指示器也可以使用數(shù)字型指示器。什么环壤?都不喜歡晒来?沒關(guān)系,你還可以實現(xiàn)Pageable接口或繼承BannerIndicator抽象類實現(xiàn)自己什么腦洞打開的指示器都沒關(guān)系镐捧。什么潜索?不會寫自定義控件臭增?沒關(guān)系可以使用任何第三方的或者任何類型的炫酷的NB的自定義控件作為指示器,只是這時你需要對BannerView設(shè)置監(jiān)聽竹习,通過回調(diào)方法void onPageSelected(BannerEntry entry, int index)來為你的自定義指示器設(shè)置指針誊抛。你想要自定義翻頁動畫?沒關(guān)系因為這個庫是基于ViewPager實現(xiàn)的整陌,所以你可以向使用ViewPager那樣對BannerView(ViewPager的子類)調(diào)用void setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer)方法設(shè)置翻頁動畫拗窃。不了解PageTransformer的可以百度、google或則直接拷貝google官方文檔中的樣板泌辫,網(wǎng)上以大堆随夸。注意,雖然BannerView是ViewPager的子類震放,但是依然支持改變翻頁動畫時長宾毒,依然支持自定義動畫差值器(可通過代碼和XML兩種方式實現(xiàn))。

·為什么說超級穩(wěn)定殿遂?答:大家都知道我們的輪播圖一般都是配合RecyclerView或ListView作為它的一個Iitem使用的诈铛。但是VeiwPager在配合RecyclerView使用時有很多問題(ListView沒有驗證過不過根據(jù)Bug的原因推測也是有問題的)。比如墨礁,當(dāng)ViewPager自動滑動到一半的時候幢竹,將其隱藏再顯示后,會出現(xiàn)無法自動滑完恩静,動畫會在隱藏時的位置卡住焕毫,直到下一次自動輪播才會恢復(fù)(只不過很多app的翻頁動畫時間過短,所以很難出現(xiàn)這種問題)驶乾。再比如邑飒,當(dāng)ViewPager完全隱藏后再次顯示則在下一次輪播時沒有動畫。還有其他的問題就不一一贅述了(以上問題在市場上的很多app都存在轻掩。)构罗。這些問題這個庫都解決了薛闪。(不知不覺寫了這么多,是不是有點王婆賣瓜抵屿?)

下面進(jìn)入正題

Gradle配置

首先要在你的Gradle中進(jìn)行配置才可以使用聚唐。

第一步:添加 JitPack 倉庫到你項目根目錄的 gradle 文件中丐重。
allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}
第二步:添加這個依賴。
dependencies {
    implementation 'com.github.kelinZhou:Banner:2.5.6'
}

XML中使用

<com.kelin.banner.view.BannerView
    android:id="@+id/vp_view_pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:bannerIndicator="@+id/biv_indicator"
    app:titleView="@+id/tv_title"
    app:pagingIntervalTime="3000"
    app:singlePageMode="canNotPaging|noIndicator"
    app:decelerateMultiple="4"
    android:background="#FFF"/>

可以看到杆查,基本所有的配置在布局中都可以完成(當(dāng)然扮惦,也提供了通過代碼配置的方法)。

指示器的使用

如果你需要指示器亲桦,本依賴庫默認(rèn)提供了兩種指示器崖蜜。你不需要在代碼中做任何事情浊仆,所有的配置都可以在XML中完成。

圓點型指示器在XML中的使用

<com.kelin.banner.view.PointIndicatorView
            android:id="@+id/biv_indicator"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:totalCount="4"
            app:pointRadius="3dp"
            app:selectedPointRadius="4dp"
            app:pointSpacing="4dp"
            app:pointColor="#5fff"
            app:selectedPointColor="@android:color/white"/>

數(shù)字型指示器在XML中的使用

<com.kelin.banner.view.NumberIndicatorView
           android:id="@+id/biv_indicator"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:textSize="16sp"
           android:textColor="@android:color/white"
           app:separator="/"
           app:separatorTextColor="@android:color/holo_green_light"
           app:currentPageTextColor="@android:color/white"
           app:totalPageTextColor="@android:color/white"
           app:totalCount="6"/>

BannerView的自定義屬性

app:pagingIntervalTime 翻頁間隔時長,用來配置每次自動翻頁之間所間隔的時間豫领,單位為毫秒抡柿。例如你想每5秒自動翻頁一次,那么該屬性應(yīng)該為5000等恐。

app:decelerateMultiple 翻頁動畫減速倍數(shù)洲劣,因為BannerView是繼承自ViewPager,所以每次自動翻頁所需要的時長都是較短的课蔬,你可以通過設(shè)置該屬性來配置減速倍數(shù)囱稽,也就是你希望每次自動翻頁所需要的時長是ViewPager原時長的多少倍。

app:bannerIndicator 為BannerView指定指示器二跋,只要是實現(xiàn)了Pageable接口的View都可以战惊,該庫中所提供的所以指示器都實現(xiàn)了Pageable接口,如果你不滿足于我提供的指示器控件扎即,那么你可以自己動手寫只要實現(xiàn)Pageable接口就可以配合BannerView使用样傍。例如樣例中的該屬性的值為:@+id/biv_indicator

app:titleView 為BannerView指定用來顯示標(biāo)題的控件,通過該屬性配置標(biāo)題控件后你就不需要監(jiān)聽BannerView的切換铺遂,然后再為標(biāo)題控件賦值衫哥。只要你配置了該屬性我會自動為你賦值。前提是你要配置的控件必須是TextView或其子類襟锐。例如樣例中的該屬性的值為:@+id/tv_title

app:subTitleView 為BannerView指定用來顯示副標(biāo)題的控件撤逢,通過該屬性配置標(biāo)題控件后你就不需要監(jiān)聽BannerView的切換,然后再為副標(biāo)題控件賦值粮坞。只要你配置了該屬性我會自動為你賦值蚊荣。前提是你要配置的控件必須是TextView或其子類。例如該屬性的值為:@+id/tv_sub_title

app:interpolator 翻頁動畫差值器莫杈,可以通過該屬性配置自動翻頁動畫的動畫差值器互例。例如該屬性的值為:@android:anim/bounce_interpolator

app:singlePageMode 因為支持無限輪播,那么只有一張圖片的時候是否還需要無限輪播筝闹?這個屬性就是用來配置當(dāng)Banner中的圖片只有一張時的處理方式的媳叨。該屬性是一個flag屬性,一共有以下兩個值:

  1. noIndicator 表示如果只有一張圖片則沒有指示器关顷。也就是說無論你是否設(shè)置了指示器糊秆,如果只有一張圖片的話那么指示器都是不顯示的。但是依然是支持無限輪播的议双。

  2. canNotPaging 表示如果只有一張圖片則不可以輪播痘番。但是如你設(shè)置了指示器的話,指示器依然會顯示。

    上面兩個屬性可以同時配置汞舱,中間用"|"符號鏈接伍纫,例如上面代碼中的配置。這樣的話如果只有一張圖片則既不會輪播而且無論你是否設(shè)置了指示器則都不會顯示昂芜。

    以上所說的只有一張圖片是指通過BannerViewsetEntries方法設(shè)置數(shù)據(jù)源時數(shù)據(jù)源集合的size()等于1翻斟。所說的設(shè)置只是器是指在XML代碼中為BannerView配置app:bannerIndicator屬性或者通過代碼BannerView.setIndicatorView(@NonNull BannerIndicator indicatorView)為BannerView設(shè)置指示器。

app:loopMode 配置輪播模式说铃,該屬性為枚舉屬性访惜,有以下三個值可以配置:

  1. infiniteLoop 無限循環(huán)輪播。
  2. fromCoverToCover 從第一頁輪播到最后一頁腻扇,然后停止輪播债热。
  3. fromCoverToCoverLoop 從第一頁輪播到最后一頁,然后再會到第一頁后再輪播到最后一頁幼苛,一直重復(fù)窒篱。

app:touchPauseEnable 用來配置觸摸暫停輪播是否可用,BannerView默認(rèn)在被觸摸時是會暫停自動輪播的舶沿,如果你不希望在BannerView被觸摸后被暫停自動輪播這可以為該屬性賦值為:false

PointIndicatorView的自定義屬性

app:totalCount 一共有多少個點(也就是總頁數(shù))墙杯,如果是配合BannerView使用的則以BannerView的頁數(shù)為準(zhǔn)。這個屬性最大的用途就是在寫布局文件時可以及時看到效果括荡,方便調(diào)試UI高镐。

android:gravity 設(shè)置偏移。只支持以下值的單一配置及合理組合:

Gravity.TOP畸冲、Gravity.BOTTOM嫉髓、View.NO_IDGravity.LEFT、View.NO_IDGravity.RIGHT邑闲、View.NO_IDGravity.START算行、View.NO_IDGravity.END、View.NO_IDGravity.CENTER苫耸、View.NO_IDGravity.CENTER_VERTICAL州邢、View.NO_IDGravity.CENTER_HORIZONTAL。

可以同時配置多個值褪子,多個值之間用"|"(或)符號連接量淌。但是不支持View.NO_IDGravity#FILL、View.NO_IDGravity#FILL_VERTICAL褐筛、View.NO_IDGravity#RELATIVE_HORIZONTAL_GRAVITY_MASK类少、以及View.NO_IDGravity#FILL_HORIZONTAL等類似配置。

app:pointSpacing 點與點之間的間距渔扎,默認(rèn)為最小的點的直徑。

app:pointRadius 點的半徑信轿。默認(rèn)為3dp晃痴。

app:selectedPointRadius 選中時點的半徑残吩,默認(rèn)與pointRadius屬性的值一直,如果你為pointRadius屬性賦值5dp倘核,那么該值的默認(rèn)值就是5dp泣侮。

app:pointColor 點的顏色。默認(rèn)為25%透明度的白色紧唱。

app:selectedPointColor 選中時點的顏色活尊,默認(rèn)為白色。

NumberIndicatorView的自定義屬性

app:totalCount 一共有多少個點(也就是總頁數(shù))漏益,如果是配合BannerView使用的則以BannerView的頁數(shù)為準(zhǔn)蛹锰。這個屬性最大的用途就是在寫布局文件時可以及時看到效果,方便調(diào)試UI绰疤。

android:gravity 設(shè)置偏移铜犬。只支持以下值的單一配置及合理組合:

android:textSize 字體大小。

android:textColor 字體顏色轻庆。

app:separator 分隔符號癣猾。例如:/

app:separatorTextColor 分割符文本顏色。

app:currentPageTextColor 當(dāng)前頁碼文本顏色余爆。

app:totalPageTextColor 總頁碼文本顏色纷宇。

代碼中使用

//找到控件。
BannerView bannerView = itemView.findViewById(R.id.vp_view_pager);
//設(shè)置數(shù)據(jù)源蛾方,默認(rèn)會啟動輪播呐粘。如果不想啟動輪播-bannerView.setEntries(entries, false);
bannerView.setEntries(entries);

設(shè)置數(shù)據(jù)源非常簡單,調(diào)用BannerView的public void setEntries(List<? extends BannerEntry> items)转捕,setEntries方法有一個重載public void setEntries(@NonNull List<? extends BannerEntry> items, boolean start)第二個參數(shù)是說你設(shè)置完數(shù)據(jù)源是否需要啟動輪播作岖。而一個參數(shù)的方法模式也是調(diào)用的兩個參數(shù)的,是默認(rèn)啟動輪播的五芝。如果你不希望輪播則調(diào)用兩個參數(shù)的方法痘儡。可以看到數(shù)據(jù)源必須是BannerEntry的子類枢步。

數(shù)據(jù)模型BannerEntry源碼

public interface BannerEntry<VALUE> {

    /**
     * 創(chuàng)建視圖View沉删。
     */
    View onCreateView(ViewGroup parent);

    /**
     * 獲取標(biāo)題。
     */
    CharSequence getTitle();

    /**
     * 獲取子標(biāo)題醉途。
     */
    CharSequence getSubTitle();

    /**
     * 獲取當(dāng)前頁面的數(shù)據(jù)矾瑰。改方法為輔助方法,是為了方便使用者調(diào)用而提供的隘擎,Api本身并沒有任何調(diào)用殴穴。如果你不需要該方法可以空實現(xiàn)。
     */
    VALUE getValue();

    /**
     * 比較兩個模型是否相同。這個方法類似于Object.equals(Object)方法采幌。
     */
    boolean same(BannerEntry newEntry);
}

大致就這幾個方法劲够,獲取標(biāo)題、獲取子標(biāo)題休傍、創(chuàng)建頁面中的View視圖征绎。為什么沒有獲取圖片的方法?因為視圖完全是自己創(chuàng)建的磨取,所以我不需要關(guān)心你的圖片是什么人柿,因為你有可能是使用本地圖片,也有可能使用網(wǎng)絡(luò)圖片忙厌。如果是網(wǎng)絡(luò)圖片的話凫岖,那么你的圖片加載器有可能是任何方式。所以視圖完全由自己創(chuàng)建慰毅。
重要介紹onCreateView方法
這個方法是需要你創(chuàng)建視圖的時候調(diào)用的隘截,你需要將你創(chuàng)建好的視圖返回,這有點像Fragment的onCreateView方法汹胃,不過你不用擔(dān)心婶芭,雖然輪播圖是無限輪播的,但是onCreateView并不是每次新的頁面顯示出來就會執(zhí)行着饥,而是你的輪播圖有幾頁就只會執(zhí)行幾次犀农,也就是說相對于當(dāng)前對象而言,只會執(zhí)行一次宰掉。當(dāng)已經(jīng)出現(xiàn)過的頁面再次進(jìn)入屏幕時不會重新執(zhí)行onCreateView呵哨,而是直接復(fù)用上一次已經(jīng)創(chuàng)建好的View。
重要介紹same方法
這個方法是在2.0版本才有的轨奄,這個是干嘛用的呢孟害?雖然注釋已經(jīng)寫的很詳細(xì)了,我還是要在啰嗦一下挪拟。因為我們設(shè)置數(shù)據(jù)源基本都是在onBindViewHolder的時候設(shè)置的挨务,而onBindViewHolder不是只調(diào)用一次,隨著你的ViewHolder在屏幕中的顯示與消失會不停的調(diào)用玉组,如果每次設(shè)置數(shù)據(jù)源都刷新視圖的話谎柄,將會有點浪費性能,所以我在設(shè)置數(shù)據(jù)源后對數(shù)據(jù)源進(jìn)行比較惯雳,如果本次設(shè)置的數(shù)據(jù)源與上一次的一致就不進(jìn)行刷新視圖的操作朝巫。但是有些東西并不是我所知道的,比如圖片石景,我不知道你是本地圖片還是網(wǎng)絡(luò)圖片劈猿,所以能提供了這樣一個方法拙吉。也是為了提高性能而提供的。

BannerEntry的兩種實現(xiàn)方式

第一種是像下面這種糙臼,我稱之為包裝實現(xiàn)方式庐镐,是講我們自己的數(shù)據(jù)模型包裝到BannerEntry的子類中

private class MyBannerEntry implements SimpleBannerEntry<MyBannerPage> {

    public MyBannerEntry(MyBannerPage bannerPage) {
        super(bannerPage);
    }

    @Override
    public View onCreateView(ViewGroup parent) {
        View entryView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_title_banner_item, parent, false);
        ImageView imageView = entryView.findViewById(R.id.iv_image);
        //這個庫沒有集成圖片框架是因為大家的項目中所使用的圖片框架可能不是都是一樣的恩商。使用什么圖片框架應(yīng)該由大家自己決定变逃,而不是依賴庫來決定。
        Glide.with(parent.getContext())
                .load(getImgUrl())
                .into(imageView);
        return entryView;
    }

    private String getImgUrl() {
        return getValue().getImgUrl();
    }

    @Override
    public CharSequence getTitle() {
        return getValue().getTitle();
    }

    @Override
    public CharSequence getSubTitle() {
        //沒有子標(biāo)題所以這里返回null怠堪。
        return null;
    }

    @Override
    public boolean same(BannerEntry newEntry) {
        return newEntry != null //兌現(xiàn)不為null
                && newEntry instanceof MyBannerEntry //類型相同
                && TextUtils.equals(newEntry.getTitle(), getTitle()) //標(biāo)題相同
                && TextUtils.equals(((MyBannerEntry) newEntry).getImgUrl(), getImgUrl()); //圖片地址相同
    }
}

這種方式適合網(wǎng)絡(luò)模型中的字段比較多揽乱,而且大多都是有用的。比如我們點擊輪播圖后要將模型攜帶到新的Activity粟矿。

第二種是下面這種懶漢實現(xiàn)方式凰棉,就是讓我們自己的模型直接實現(xiàn)BannerEntry接口

public class MyBannerEntry implements BannerEntry<String> {
    private final String webUrl;
    private String title;
    private String subTitle;
    private String imgUrl;

    MyBannerEntry(String title, String subTitle, String imgUrl, String webUrl) {
        this.title = title;
        this.subTitle = subTitle;
        this.imgUrl = imgUrl;
        this.webUrl = webUrl;
    }

    @Override
    public View onCreateView(ViewGroup parent) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_title_banner_item, parent, false);
        ImageView imageView = (ImageView) view.findViewById(R.id.iv_image);
        Glide.with(parent.getContext())
                .load(imgUrl)
                .into(imageView);
        return view;
    }

    /**
     * 獲取標(biāo)題
     *
     * @return 返回當(dāng)前條目的標(biāo)題。
     */
    @Override
    public CharSequence getTitle() {
        return title;
    }

    /**
     * 獲取子標(biāo)題陌粹。
     *
     * @return 返回當(dāng)前條目的子標(biāo)題撒犀。
     */
    @Nullable
    @Override
    public CharSequence getSubTitle() {
        return subTitle;
    }

    /**
     * 獲取當(dāng)前頁面的數(shù)據(jù)。
     *
     * @return 返回當(dāng)前頁面的數(shù)據(jù)掏秩。
     */
    @Override
    public String getValue() {
        return webUrl;
    }

    @Override
    public boolean same(BannerEntry newEntry) {
        return newEntry instanceof MyBannerEntry 
                && TextUtils.equals(title, newEntry.getTitle()) 
                && TextUtils.equals(subTitle, newEntry.getSubTitle()) 
                && TextUtils.equals(imgUrl, ((MyBannerEntry) newEntry).imgUrl)
                && TextUtils.equals(webUrl, ((MyBannerEntry) newEntry).webUrl);
    }
}

這種方式為什么我說是懶漢式呢或舞?因為我是直接用網(wǎng)絡(luò)數(shù)據(jù)模型實現(xiàn)BannerEntry接口,這么做就不用在做模型轉(zhuǎn)換蒙幻,從網(wǎng)絡(luò)框架中得到的數(shù)據(jù)就直接可以使用映凳。比較適合喜歡偷懶且數(shù)據(jù)模型中沒有太多字段,或大多字段都沒有什么用處邮破。

設(shè)置監(jiān)聽

頁面點擊監(jiān)聽

bannerView.setOnPageClickListener(new BannerView.OnPageClickListener() {
    @Override
    protected void onPageClick(BannerEntry entry, int index) {
        //某個頁面被單擊后執(zhí)行诈豌,entry就是這個頁面的數(shù)據(jù)模型。index是頁面索引抒和,從0開始矫渔。
    }
});

頁面長按監(jiān)聽

bannerView.setOnPageLongClickListener(new BannerView.OnPageLongClickListener() {
    @Override
    public void onPageLongClick(BannerEntry entry, int index) {
        //某個頁面被長按后執(zhí)行,entry就是這個頁面的數(shù)據(jù)模型摧莽。index是頁面索引庙洼,從0開始。
    }
});

頁面改變監(jiān)聽

bannerView.setOnPageChangedListener(new BannerView.OnPageChangeListener() {
    @Override
    public void onPageSelected(BannerEntry entry, int index) {
        //某個頁面被選中后執(zhí)行范嘱,entry就是這個頁面的數(shù)據(jù)模型送膳。index是頁面索引,從0開始丑蛤。
    }

    @Override
    public void onPageScrolled(int index, float positionOffset, int positionOffsetPixels) {
        //頁面滑動中執(zhí)行叠聋,這個與ViewPage的回調(diào)一致。
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        //頁面滑動的狀態(tài)被改變時執(zhí)行受裹,也是與ViewPager的回調(diào)一致碌补。
    }
});

到這里貌似都說完了虏束,可能我說的有點啰嗦了有人更喜歡通過看代碼了解,下面我吧完整的代碼發(fā)出來吧厦章,便于閱讀我都寫成了內(nèi)部類镇匀。

Demo中所有的代碼

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        RecyclerView recyclerView = findViewById(R.id.rv_list);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        MyRecyclerViewAdapter adapter = new MyRecyclerViewAdapter(getData());
        recyclerView.setAdapter(adapter);
    }

    @SuppressWarnings("unchecked")
    public List getData() {
        List list = new ArrayList();
        list.add(getBannerPagers());
        for (int i = 0; i < 100; i++) {
            list.add("我是條目" + i);
        }
        return list;
    }

    public List<MyBannerPage> getBannerPagers() {
        List<MyBannerPage> list = new ArrayList<>();
        //下面的BannerPage就好比是你從網(wǎng)絡(luò)上獲取到的數(shù)據(jù)模型,大家能明白這個意思就行袜啃。
        MyBannerPage bannerPage1 = new MyBannerPage("大話西游:“炸毛韜”引誘老妖", "http://m.qiyipic.com/common/lego/20171026/dd116655c96d4a249253167727ed37c8.jpg");
        MyBannerPage bannerPage2 = new MyBannerPage("天使之路:藏風(fēng)大片遇高反危機(jī)", "http://m.qiyipic.com/common/lego/20171029/c9c3800f35f84f1398b89740f80d8aa6.jpg");
        MyBannerPage bannerPage3 = new MyBannerPage("星空海2:陸漓設(shè)局害慘吳居藍(lán)", "http://m.qiyipic.com/common/lego/20171023/bd84e15d8dd44d7c9674218de30ac75c.jpg");
        MyBannerPage bannerPage4 = new MyBannerPage("中國職業(yè)脫口秀大賽:狂笑首播", "http://m.qiyipic.com/common/lego/20171028/f1b872de43e649ddbf624b1451ebf95e.jpg");
        MyBannerPage bannerPage5 = new MyBannerPage("奇秀好音樂汗侵,你身邊的音樂真人秀", "http://pic2.qiyipic.com/common/20171027/cdc6210c26e24f08940d36a5eb918c34.jpg");

        //將我們所有的BannerPage的實現(xiàn)類都放入的List集合中。
        list.add(bannerPage1);
        list.add(bannerPage2);
        list.add(bannerPage3);
        list.add(bannerPage4);
        list.add(bannerPage5);
        return list;
    }

    private class MyRecyclerViewAdapter extends RecyclerView.Adapter {

        private List items;

        MyRecyclerViewAdapter(List items) {
            this.items = items;
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == 0) {
                return new BannerViewHolder(parent);
            } else {
                return new ItemViewHolder(parent);
            }
        }

        @Override
        public int getItemViewType(int position) {
            return position == 0 ? 0 : 1;
        }

        @Override
        @SuppressWarnings("unchecked")
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
            if (getItemViewType(position) == 0) {
                BannerViewHolder viewHolder = (BannerViewHolder) holder;
                List<MyBannerPage> o = (List<MyBannerPage>) items.get(position);
                ArrayList<MyBannerEntry> entries = new ArrayList<>();
                for (MyBannerPage page : o) {
                    entries.add(new MyBannerEntry(page));
                }
                viewHolder.mBannerView.setEntries(entries);
            } else {
                ItemViewHolder viewHolder = (ItemViewHolder) holder;
                viewHolder.mTextView.setText((String) items.get(position));
            }
        }

        @Override
        public int getItemCount() {
            return items == null ? 0 : items.size();
        }
    }

    private class BannerViewHolder extends RecyclerView.ViewHolder {
        private final BannerView mBannerView;

        BannerViewHolder(ViewGroup parent) {
            super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_banner_layout, parent, false));
            mBannerView = itemView.findViewById(R.id.vp_view_pager);
            mBannerView.setOnPageClickListener(new BannerView.OnPageClickListener() {
                @Override
                protected void onPageClick(BannerEntry entry, int index) {
                    //因為index是索引而索引是從0開始的所以表示頁數(shù)是:index+1
                    Toast.makeText(getApplicationContext(), String.format(Locale.CHINA, "您點擊了BannerView的第%d頁群发!", index + 1), Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

    private class ItemViewHolder extends RecyclerView.ViewHolder {
        private final TextView mTextView;

        ItemViewHolder(ViewGroup parent) {
            super(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_normal_layout, parent, false));
            mTextView = (TextView) itemView;
        }
    }

    private class MyBannerEntry implements BannerEntry<MyBannerPage> {

        private MyBannerPage mBannerPage;

        public MyBannerEntry(MyBannerPage bannerPage) {
            mBannerPage = bannerPage;
        }

        @Override
        public View onCreateView(ViewGroup parent) {
            View entryView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_title_banner_item, parent, false);
            ImageView imageView = entryView.findViewById(R.id.iv_image);
            //這個庫沒有集成圖片框架是因為大家的項目中所使用的圖片框架可能不是都是一樣的晰韵。使用什么圖片框架應(yīng)該由大家自己決定,而不是依賴庫來決定熟妓。
            Glide.with(parent.getContext())
                    .load(getImgUrl())
                    .into(imageView);
            return entryView;
        }

        private String getImgUrl() {
            return mBannerPage.getImgUrl();
        }

        @Override
        public CharSequence getTitle() {
            return mBannerPage.getTitle();
        }

        @Override
        public CharSequence getSubTitle() {
            //沒有子標(biāo)題所以這里返回null雪猪。
            return null;
        }

        @Override
        public MyBannerPage getValue() {
            //這個方法api本身沒有任何調(diào)用,也可以空實現(xiàn)起愈。是為方便開發(fā)者而提供的只恨。有點類似于View.getTag()方法。
            return mBannerPage;
        }

        @Override
        public boolean same(BannerEntry newEntry) {
            return newEntry != null //兌現(xiàn)不為null
                    && newEntry instanceof MyBannerEntry //類型相同
                    && TextUtils.equals(newEntry.getTitle(), getTitle()) //標(biāo)題相同
                    && TextUtils.equals(((MyBannerEntry) newEntry).getImgUrl(), getImgUrl()); //圖片地址相同
        }
    }

    private class MyBannerPage {
        private String title;
        private String imgUrl;

        public MyBannerPage(String title, String imgUrl) {
            this.title = title;
            this.imgUrl = imgUrl;
        }

        public String getTitle() {
            return title;
        }

        public String getImgUrl() {
            return imgUrl;
        }
    }
}

Demo中所有的布局文件

R.layout.activity_main

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rv_list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

R.layout.item_banner_layout

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:app="http://schemas.android.com/apk/res-auto"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="175dp"
                android:orientation="vertical">

    <com.kelin.banner.view.BannerView
        android:id="@+id/vp_view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:bannerIndicator="@+id/biv_indicator"
        app:titleView="@+id/tv_title"
        app:pagingIntervalTime="3000"
        app:singlePageMode="canNotPaging|noIndicator"
        app:decelerateMultiple="4"
        android:background="#FFF"/>

    <LinearLayout android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:layout_alignParentBottom="true"
                  android:background="#8000"
                  android:gravity="center_vertical"
                  android:orientation="horizontal"
                  android:padding="6dp">

        <!--用來顯示標(biāo)題的控件-->
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:textColor="@android:color/white"
            android:textSize="15sp"
            android:textStyle="bold"
            tools:text="我是標(biāo)題抬虽!"/>

        <!--Banner的圓點型指示器-->
        <com.kelin.banner.view.PointIndicatorView
            android:id="@+id/biv_indicator"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:totalCount="4"
            app:pointRadius="3dp"
            app:selectedPointRadius="4dp"
            app:pointSpacing="4dp"
            app:pointColor="#5fff"
            app:selectedPointColor="@android:color/white"/>
    </LinearLayout>
</RelativeLayout>

R.layout.item_normal_layout

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:paddingBottom="16dp"
          android:paddingLeft="8dp"
          android:paddingRight="8dp"
          android:paddingTop="18dp"
          android:textColor="@android:color/black"
          android:textSize="16sp"
          tools:text="條目一"/>

R.layout.layout_title_banner_item

<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
           xmlns:tools="http://schemas.android.com/tools"
           android:id="@+id/iv_image"
           android:layout_width="match_parent"
           android:layout_height="match_parent"
           android:scaleType="centerCrop"/>

如果需要源碼請點擊這里, 如果你覺得有用就幫我點個Star官觅。你的支持是我繼續(xù)創(chuàng)作的動力!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斥赋,一起剝皮案震驚了整個濱河市缰猴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌疤剑,老刑警劉巖滑绒,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異隘膘,居然都是意外死亡疑故,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門弯菊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纵势,“玉大人,你說我怎么就攤上這事管钳∏仗” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵才漆,是天一觀的道長牛曹。 經(jīng)常有香客問我,道長醇滥,這世上最難降的妖魔是什么黎比? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任超营,我火速辦了婚禮,結(jié)果婚禮上阅虫,老公的妹妹穿的比我還像新娘演闭。我一直安慰自己,他們只是感情好颓帝,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布米碰。 她就那樣靜靜地躺著,像睡著了一般躲履。 火紅的嫁衣襯著肌膚如雪见间。 梳的紋絲不亂的頭發(fā)上聊闯,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天工猜,我揣著相機(jī)與錄音,去河邊找鬼菱蔬。 笑死篷帅,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拴泌。 我是一名探鬼主播魏身,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蚪腐!你這毒婦竟也來了箭昵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤回季,失蹤者是張志新(化名)和其女友劉穎家制,沒想到半個月后,有當(dāng)?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
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留谚赎,地道東北人淫僻。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像壶唤,于是被迫代替她去往敵國和親雳灵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

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