Yasha (夜叉)
物品介紹:
基于Kotlin的現(xiàn)代化RecyclerView渲染武器
物品特點(diǎn):
- 無(wú)需Adapter
- 無(wú)需ViewHolder
- 支持初始化數(shù)據(jù)加載
- 支持?jǐn)?shù)據(jù)分頁(yè)加載
- 支持MultiViewType
- 支持Header和Footer
- 支持DiffUtil
- 支持Loading State
- 支持CleanUp, 釋放資源避免內(nèi)存泄漏
First Blood
如何快速渲染一個(gè)RecyclerView病线?還在不厭其煩的寫Adapter,ViewHolder? 快讓夜叉來(lái)拯救你吧:
//以 **dataSource** 作為數(shù)據(jù)源渲染一個(gè)列表
recycler_view.linear(dataSource) {
//渲染一個(gè)NormalItem類型的Item
renderItem<NormalItem> {
//布局文件
res(R.layout.view_holder_normal)
//綁定數(shù)據(jù)
onBind {
tv_normal_content.text = data.toString()
}
}
//渲染一個(gè)HeaderItem類型的頭布局
renderItem<HeaderItem> {
//布局文件
res(R.layout.view_holder_header)
//綁定數(shù)據(jù)
onBind {
tv_header_content.text = data.toString()
}
}
//渲染一個(gè)FooterItem類型的尾部
renderItem<FooterItem> {
//布局文件
res(R.layout.view_holder_footer)
//綁定數(shù)據(jù)
onBind {
tv_footer_content.text = data.toString()
}
}
}
如你所見(jiàn)绑莺,非常簡(jiǎn)單并且直觀惕耕,并且沒(méi)有看到任何的Adapter以及ViewHolder,裝備夜叉欺缘,去Gank吧谚殊!
Double Kill
渲染搞定了,數(shù)據(jù)源從何而來(lái)呢丛肢?夜叉貼心的為你準(zhǔn)備了它的好伙伴:散華
散華是另一件強(qiáng)大的武器摔踱,它能提供夜叉所需要的任何數(shù)據(jù)怨愤,有了它夜叉才能如魚(yú)得水,就像在Dota中它倆也是形影不離篮愉,熟悉Dota的朋友都知道差导,夜叉+散華=暗夜對(duì)劍,所以這里也是一樣设褐,有了它們倆助析,何懼任何逆風(fēng)局?
//創(chuàng)建一個(gè)DataSource
class DemoDataSource : YashaDataSource() {
//loadInitial負(fù)責(zé)加載列表初始化數(shù)據(jù)
override fun loadInitial(loadCallback: LoadCallback<YashaItem>) {
//模擬延時(shí)寡键,不用擔(dān)心雪隧,該方法會(huì)在異步線程中執(zhí)行脑沿,因此你可以放心在這里進(jìn)行網(wǎng)絡(luò)請(qǐng)求或者數(shù)據(jù)庫(kù)加載等等
Thread.sleep(1500)
val allDataList = mutableListOf<YashaItem>()
//添加Header數(shù)據(jù)
for (i in 0 until 2) {
allDataList.add(HeaderItem(i))
}
//添加Item數(shù)據(jù)
for (i in 0 until 10) {
allDataList.add(NormalItem(i))
}
//添加Footer數(shù)據(jù)
for (i in 0 until 2) {
allDataList.add(FooterItem(i))
}
//通知數(shù)據(jù)加載完畢
loadCallback.setResult(allDataList)
}
//loadAfter負(fù)責(zé)加載下一頁(yè)數(shù)據(jù),夜叉會(huì)自己決定是否觸發(fā)了分頁(yè)加載注服,你只需要做好加載下一頁(yè)的邏輯,其他的交給夜叉吧
override fun loadAfter(loadCallback: LoadCallback<YashaItem>) {
//當(dāng)加載失敗:
if (page % 3 == 0) {
//當(dāng)數(shù)據(jù)加載失敗時(shí)可很,只需要簡(jiǎn)單告訴夜叉一個(gè)NULL值我抠,夜叉就會(huì)自動(dòng)停止加載,并顯示一個(gè)加載失敗的狀態(tài)
loadCallback.setResult(null)
return
}
//當(dāng)加載完畢:
if(page == 5) {
//當(dāng)數(shù)據(jù)加載完之后菜拓,只需要告訴夜叉一個(gè)空列表纳鼎,夜叉就會(huì)自動(dòng)停止加載裳凸,并且顯示一個(gè)加載完畢的狀態(tài)
loadCallback.setResult(emptyList())
return
}
//加載下一頁(yè)數(shù)據(jù):
val items = mutableListOf<YashaItem>()
for (i in page * 10 until (page + 1) * 10) {
items.add(NormalItem(i))
}
loadCallback.setResult(items)
}
}
是不是很輕松?沒(méi)錯(cuò)逗宁,夜叉和散華提供的API簡(jiǎn)單易懂瞎颗,無(wú)需任何門檻即可快速上手捌议,簡(jiǎn)直是居家旅行禁灼,殺人越貨必備的武器!
除此之外弄捕,散華還提供了很多直接操作數(shù)據(jù)源的API守谓,例如
//Headers
fun addHeader(t: T, position: Int = -1, delay: Boolean = false)
fun addHeaders(list: List<T>, position: Int = -1, delay: Boolean = false)
fun removeHeader(t: T, delay: Boolean = false)
fun setHeader(old: T, new: T, delay: Boolean = false)
fun getHeader(position: Int): T
fun clearHeader(delay: Boolean = false)
//Footers
fun addFooter(t: T, position: Int = -1, delay: Boolean = false)
fun addFooters(list: List<T>, position: Int = -1, delay: Boolean = false)
fun removeFooter(t: T, delay: Boolean = false)
fun setFooter(old: T, new: T, delay: Boolean = false)
fun getFooter(position: Int): T
fun clearFooter(delay: Boolean = false)
//Items
fun addItem(t: T, position: Int = -1, delay: Boolean = false)
fun addItems(list: List<T>, position: Int = -1, delay: Boolean = false)
fun removeItem(t: T, delay: Boolean = false)
fun setItem(old: T, new: T, delay: Boolean = false)
fun getItem(position: Int): T
fun clearItem(delay: Boolean = false)
//等等API接口
Triple Kill
除此之外斋荞,夜叉還貼心的為各位小哥們準(zhǔn)備了狀態(tài)的顯示,如常用的加載中凤优,加載失敗筑辨,加載完成 等
那如果對(duì)自帶的狀態(tài)有任何不滿,那很簡(jiǎn)單暮现,第一種辦法就是干掉它楚昭,第二種辦法就是替換它
//干掉它:
class DemoDataSource : YashaDataSource() {
override fun onStateChanged(newState: Int) {
//super.onStateChanged(newState)
//只需要重新這個(gè)方法并且注釋掉super的調(diào)用即可抚太,這樣就沒(méi)有任何狀態(tài)顯示啦!
}
}
//替換它:
recycler_view.linear(dataSource) {
//替換成你自己的狀態(tài)渲染方式
renderItem<YashaStateItem> {
//新的狀態(tài)布局
res(R.layout.your_state_view)
//新的狀態(tài)綁定
onBind {
}
gridSpanSize(spanCount)
staggerFullSpan(true)
}
}