Kotlin学习之DslAdapter

又开始学习kotlin了,Adapter的库在github也是一找一大堆,这次Dsl就用它来学习吧,DataBinding(支持多布局)

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
val mAdapter = MagicAdapter.repositoryAdapter()
.addItemDsl<String> {
resId = R.layout.item_string
dataMatch = { d, _ -> d is String }
itemId(BR.user) { User(1234567, "GoGo") }
handler(BR.presenter, View.OnClickListener {
Toast.makeText(this@MainActivity, R.string.item_string, Toast.LENGTH_LONG).show()
})
areItems = { o, n -> o == n }
}
.addItemDsl<User> {
resId = R.layout.item_user
dataMatch = { d, _ -> d is User }
handler(BR.presenter, View.OnClickListener {
Toast.makeText(this@MainActivity, R.string.item_user, Toast.LENGTH_LONG).show()
})
areItems = { o, n -> o.id == n.id }
areContents = { o, n -> o.id == n.id && o.name == n.name}
}
.build()
binding.rv.run {
adapter = mAdapter
layoutManager = LinearLayoutManager(this@MainActivity)
}
val data = ArrayList<Any>()
data.add("11111")
data.add("22222")
data.add("33333")
data.add("44444")
data.add("44444")
data.add(User(111, "张三"))
data.add(User(222, "李四"))
data.add(User(333, "王五"))
data.add(User(444, "桃六"))
mAdapter.submitList(data)

主要方法介绍addItemDsl()方法代表添加一个布局可以指定类型,传入一个MagicItem类,resId代码布局id,dataMatch是之在多布局的时候,当前item的数据和你加入的布局类型是否符合,因为是DataBinding版本,所以在布局上默认有个BR.item的,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
<data>
<variable
name="item"
type="String"/>
<variable name="user" type="com.github.wkw.magicadapter.User"/>
<variable
name="presenter"
type="android.view.View.OnClickListener"/>
</data>

itemId方法就是可以给布局加入其它类型的比如我加入了User类型,handler方法也是传人id和函数,因为有时候你会onClick,onLongClick自己可以加入。areItems和areContents代表的意思是加入了DiffUtil.Callback() 里面的两个areItemsTheSame和areContentsTheSame方法。

原理

MagicAdapter里面

1
2
3
4
5
private var datas: MutableList<Any> = ArrayList()
internal val items: MutableList<MagicItem<Any>> = builder.items
private val positionToTypeMap = SparseIntArray()

item就是记录所以的布局总和,如何通过position来找到对应的布局核心代码就是如下

1
2
3
4
5
6
7
8
9
10
11
12
private fun positionToItemsIndex(position: Int): Int {
if (items.isEmpty()) {
throw RuntimeException("item must add")
}
items.forEachIndexed { index, magicItem ->
if (magicItem.getItemViewType(datas[position], position)) {
positionToTypeMap.put(position, index)
return index
}
}
throw RuntimeException("can't find matched item")
}

onBindViewHolder默认

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
override fun onBindViewHolder(holder: BindingViewHolder<ViewDataBinding>, postion: Int) {
val data = datas[postion]
val magicItem = items[positionToTypeMap.get(postion)]
holder.binding.setVariable(BR.item, data)
val handlers = magicItem.handlers()
for ((id, handle) in handlers) {
holder.binding.setVariable(id, handle)
}
val itemIds = magicItem.itemIds()
for ((idGet, setter) in itemIds) {
val itemVariable = idGet(data)
holder.binding.setVariable(itemVariable, setter(data))
}
holder.binding.executePendingBindings()
}

其实代码量很少。

支持Dsl

MagicDslItem类来支持

不足之处

目前只支持databinding版本后期可以支持普通版本,DataBindingDslAdapter