封裝那些事-RecyclerView封裝實(shí)踐

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

來(lái)上圖:


recycler01.png

recycler02.png

相關(guān)說(shuō)明:

  1. 該列表頁(yè)可以是Activity,也可以是Fragment
  2. 該列表頁(yè)使用RecyclerView,所以支持列表,網(wǎng)格,瀑布流
  3. 該列表頁(yè)支持下拉刷新,自動(dòng)加載更多
  4. 該列表需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)

  1. 指定列表類型:linear, grid, stagger
  2. 指定item對(duì)應(yīng)的ViewHolder
  3. 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)去看看吧。

recycler03.png

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

    android.app.ListActivity
recycler04.png

這里實(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è)坑。

  1. 判斷是否需要加載更多,是通過(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
  2. 加載更多footer需要自成一行,但在grid和stagger模式下,這個(gè)就比較麻煩了。GridLayoutManager還簡(jiǎn)單一點(diǎn),直接看源碼的類注釋你就能知道如何做。SpanSizeLookup,如果為footer,那就返回1,代表占滿整個(gè)寬度。
    recycler06.png

    StaggerGridLayoutManager更麻煩,你得改itemView的LayoutParams,將setFullSpan設(shè)為true,才能自成一行。
    recycler07.png
    recycler08.png
  3. 以前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。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容