今天要跟大家安利一種封裝方式,保證只用100行代碼就能擼一個列表頁面。
來上圖:
相關說明:
- 該列表頁可以是Activity,也可以是Fragment
- 該列表頁使用RecyclerView,所以支持列表,網格,瀑布流
- 該列表頁支持下拉刷新,自動加載更多
- 該列表需extends BaseListActivity或BaseListFragment
之前Stay寫過一篇RecyclerView再封裝,本篇是對該篇的詳細解釋。
本文難度適中,沒有過多的算法,純粹是利用Android提供的API與一些設計模式相結合做的封裝。
沒什么好解釋的了,老司機要開車啦,滴滴。。
首先來看看我們這個列表SampleListActivity, 它是繼承BaseListActivity
public class SampleListActivity extends BaseListActivity<String>
注意,此處有泛型。這里的T就是你用在列表數據List<T>。為什么要這樣寫,先埋個坑,一會再填。
在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只需要做以上實現
- 指定列表類型:linear, grid, stagger
- 指定item對應的ViewHolder
- ViewHolder的數據綁定
ok,只要完成這些事情,一個妹子列表就出來了。開擼吧。
好奇的你不會就此滿足。Adapter哪去了?RecyclerView呢?我怎么沒看到它們。嗯哼~
BaseListActivity有個兒子叫SampleListActivity, 兒子非常努力,憑借自己的天賦找到了組織,終于,3秒后,兒子拿著請求來的數據加上老爹給的框架擼上了妹紙。注:妹紙圖來自gank.io
就是這樣一個情況,除了請求數據以及制定每個Item的UI樣式,其他的都由父類完成。
是不是好奇BaseListActivity中封裝了些什么?我們進去看看吧。
其實SampleListActivity還有個爺爺,不過這不重要。我們看,在父類中定義了ArrayList<T>, Adapter, Recycler. 并且對Recycler, Adapter做了初始化,為什么要這樣寫?老司機帶你看一下系統源碼就知道了。
android.app.ListActivity
這里實際上參考了系統ListActivity的初衷,將ListView(這里是RecyclerView)封裝起來,并且定義一個默認layout,當列表頁非常簡單時,子類只需要綁定data就可以完成UI顯示。
Stay這里做的BaseListActivity要更內聚一些。因為我們將List<T>定義在父類,所以在Adapter的getItemCount中可以直接做返回。不需要子類明確指定size。至于其它父類定義不了的,比如onCreateViewHolder, onBindViewHolder,可以讓子類實現。
還有父類預定義了列表樣式,默認為LinearLayoutManager,如果子類不想要,直接重寫方法就可以了。
其實這個父類代碼也不多,90行。父類有父類的想法,為了兒子能自己獨立成長,只能提供一些最基礎的框架,至于兒子以后能干嘛,那是兒子的事情。
雖然父類做的事情不多,但是能給的都給了,它做的最正確的事,就是早年還做了一套封裝,它叫PullRecycler。這個PullRecycler還挺給力的,可以下拉刷新,自動加載更多,支持三種LayoutManager。
其實這個PullRecycler沒有多難做,也就是一個SwipeRefreshLayout+RecyclerView。當然難點還是有的。下拉刷新是SwipeRefreshLayout實現的,但是自動加載更多有三個坑。
-
判斷是否需要加載更多,是通過onScrollListener來做的,你需要拿屏幕中最后一個顯示的item posistion去跟totalCount比對。但是在StaggerLayoutManager中,拿到的是一個數組。其它LayoutManager拿到的是int。這就坑了,不統一,很多github上的RecyclerView封裝都是通過instanceOf來強轉的,我不太喜歡。所以我就定義了一個接口ILayoutManager,讓每個LayoutManager去實現一個統一的findLastVisiblePosition() recycler05.png
-
加載更多footer需要自成一行,但在grid和stagger模式下,這個就比較麻煩了。GridLayoutManager還簡單一點,直接看源碼的類注釋你就能知道如何做。SpanSizeLookup,如果為footer,那就返回1,代表占滿整個寬度。recycler06.pngrecycler07.pngrecycler08.png
-
以前ListView可以添加footer,但是RecyclerView沒有,你得自己在adapter中做判斷,如果有footer,那itemCount要+1。所以我又將Adapter抽出來,做成BaseListAdapter,是否顯示footer,判斷是否是stagger模式下footer,給一個默認footerViewHolder,如果子類不滿意還能再重寫。recycler09.png
啊啊啊,開車好累,老司機得歇會。
附上源碼github,自己拿去開吧。直接可以運行,另外還封裝了BaseSectionListActivity, 帶section header的sample。