今天要跟大家安利一種封裝方式,保證只用100行代碼就能擼一個(gè)列表頁(yè)面。
來(lái)上圖:


相關(guān)說(shuō)明:
- 該列表頁(yè)可以是Activity,也可以是Fragment
- 該列表頁(yè)使用RecyclerView,所以支持列表,網(wǎng)格,瀑布流
- 該列表頁(yè)支持下拉刷新,自動(dòng)加載更多
- 該列表需extends BaseListActivity或BaseListFragment
之前Stay寫過(guò)一篇RecyclerView再封裝,本篇是對(duì)該篇的詳細(xì)解釋。
本文難度適中,沒(méi)有過(guò)多的算法,純粹是利用Android提供的API與一些設(shè)計(jì)模式相結(jié)合做的封裝。
沒(méi)什么好解釋的了,老司機(jī)要開車?yán)?,滴滴?!?/p>
首先來(lái)看看我們這個(gè)列表SampleListActivity, 它是繼承BaseListActivity
public class SampleListActivity extends BaseListActivity<String>
注意,此處有泛型。這里的T就是你用在列表數(shù)據(jù)List<T>。為什么要這樣寫,先埋個(gè)坑,一會(huì)再填。
在SampleListActivity中
@Override
protected BaseViewHolder getViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_sample_list_item, parent, false);
return new SampleViewHolder(view);
}
@Override
protected ILayoutManager getLayoutManager() {
return new MyGridLayoutManager(getApplicationContext(), 3);
}
class SampleViewHolder extends BaseViewHolder {
}
子類SampleListActivity只需要做以上實(shí)現(xiàn)
- 指定列表類型:linear, grid, stagger
- 指定item對(duì)應(yīng)的ViewHolder
- ViewHolder的數(shù)據(jù)綁定
ok,只要完成這些事情,一個(gè)妹子列表就出來(lái)了。開擼吧。
好奇的你不會(huì)就此滿足。Adapter哪去了?RecyclerView呢?我怎么沒(méi)看到它們。嗯哼~
BaseListActivity有個(gè)兒子叫SampleListActivity, 兒子非常努力,憑借自己的天賦找到了組織,終于,3秒后,兒子拿著請(qǐng)求來(lái)的數(shù)據(jù)加上老爹給的框架擼上了妹紙。注:妹紙圖來(lái)自gank.io
就是這樣一個(gè)情況,除了請(qǐng)求數(shù)據(jù)以及制定每個(gè)Item的UI樣式,其他的都由父類完成。
是不是好奇BaseListActivity中封裝了些什么?我們進(jìn)去看看吧。

其實(shí)SampleListActivity還有個(gè)爺爺,不過(guò)這不重要。我們看,在父類中定義了ArrayList<T>, Adapter, Recycler. 并且對(duì)Recycler, Adapter做了初始化,為什么要這樣寫?老司機(jī)帶你看一下系統(tǒng)源碼就知道了。
android.app.ListActivity

這里實(shí)際上參考了系統(tǒng)ListActivity的初衷,將ListView(這里是RecyclerView)封裝起來(lái),并且定義一個(gè)默認(rèn)layout,當(dāng)列表頁(yè)非常簡(jiǎn)單時(shí),子類只需要綁定data就可以完成UI顯示。
Stay這里做的BaseListActivity要更內(nèi)聚一些。因?yàn)槲覀儗ist<T>定義在父類,所以在Adapter的getItemCount中可以直接做返回。不需要子類明確指定size。至于其它父類定義不了的,比如onCreateViewHolder, onBindViewHolder,可以讓子類實(shí)現(xiàn)。
還有父類預(yù)定義了列表樣式,默認(rèn)為L(zhǎng)inearLayoutManager,如果子類不想要,直接重寫方法就可以了。
其實(shí)這個(gè)父類代碼也不多,90行。父類有父類的想法,為了兒子能自己獨(dú)立成長(zhǎng),只能提供一些最基礎(chǔ)的框架,至于兒子以后能干嘛,那是兒子的事情。
雖然父類做的事情不多,但是能給的都給了,它做的最正確的事,就是早年還做了一套封裝,它叫PullRecycler。這個(gè)PullRecycler還挺給力的,可以下拉刷新,自動(dòng)加載更多,支持三種LayoutManager。
其實(shí)這個(gè)PullRecycler沒(méi)有多難做,也就是一個(gè)SwipeRefreshLayout+RecyclerView。當(dāng)然難點(diǎn)還是有的。下拉刷新是SwipeRefreshLayout實(shí)現(xiàn)的,但是自動(dòng)加載更多有三個(gè)坑。
-
判斷是否需要加載更多,是通過(guò)onScrollListener來(lái)做的,你需要拿屏幕中最后一個(gè)顯示的item posistion去跟totalCount比對(duì)。但是在StaggerLayoutManager中,拿到的是一個(gè)數(shù)組。其它LayoutManager拿到的是int。這就坑了,不統(tǒng)一,很多github上的RecyclerView封裝都是通過(guò)instanceOf來(lái)強(qiáng)轉(zhuǎn)的,我不太喜歡。所以我就定義了一個(gè)接口ILayoutManager,讓每個(gè)LayoutManager去實(shí)現(xiàn)一個(gè)統(tǒng)一的findLastVisiblePosition() recycler05.png
-
加載更多footer需要自成一行,但在grid和stagger模式下,這個(gè)就比較麻煩了。GridLayoutManager還簡(jiǎn)單一點(diǎn),直接看源碼的類注釋你就能知道如何做。SpanSizeLookup,如果為footer,那就返回1,代表占滿整個(gè)寬度。StaggerGridLayoutManager更麻煩,你得改itemView的LayoutParams,將setFullSpan設(shè)為true,才能自成一行。recycler06.pngrecycler07.pngrecycler08.png
-
以前ListView可以添加footer,但是RecyclerView沒(méi)有,你得自己在adapter中做判斷,如果有footer,那itemCount要+1。所以我又將Adapter抽出來(lái),做成BaseListAdapter,是否顯示footer,判斷是否是stagger模式下footer,給一個(gè)默認(rèn)footerViewHolder,如果子類不滿意還能再重寫。recycler09.png
啊啊啊,開車好累,老司機(jī)得歇會(huì)。
附上源碼github,自己拿去開吧。直接可以運(yùn)行,另外還封裝了BaseSectionListActivity, 帶section header的sample。




