按照慣例先上效果圖:
還有各種效果
體驗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屬性,一共有以下兩個值:
noIndicator
表示如果只有一張圖片則沒有指示器关顷。也就是說無論你是否設(shè)置了指示器糊秆,如果只有一張圖片的話那么指示器都是不顯示的。但是依然是支持無限輪播的议双。-
canNotPaging
表示如果只有一張圖片則不可以輪播痘番。但是如你設(shè)置了指示器的話,指示器依然會顯示。上面兩個屬性可以同時配置汞舱,中間用"|"符號鏈接伍纫,例如上面代碼中的配置。這樣的話如果只有一張圖片則既不會輪播而且無論你是否設(shè)置了指示器則都不會顯示昂芜。
以上所說的只有一張圖片是指通過
BannerView
的setEntries
方法設(shè)置數(shù)據(jù)源時數(shù)據(jù)源集合的size()
等于1翻斟。所說的設(shè)置只是器是指在XML代碼中為BannerView配置app:bannerIndicator
屬性或者通過代碼BannerView.setIndicatorView(@NonNull BannerIndicator indicatorView)
為BannerView設(shè)置指示器。
app:loopMode
配置輪播模式说铃,該屬性為枚舉屬性访惜,有以下三個值可以配置:
-
infiniteLoop
無限循環(huán)輪播。 -
fromCoverToCover
從第一頁輪播到最后一頁腻扇,然后停止輪播债热。 -
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"/>