https://github.com/xuexiangjys/databindingsample
DataBinding使用集合
https://github.com/xuexiangjys/databindingsample
databinding samples x-samples
Last synced: 8 months ago
JSON representation
DataBinding使用集合
- Host: GitHub
- URL: https://github.com/xuexiangjys/databindingsample
- Owner: xuexiangjys
- License: apache-2.0
- Created: 2022-07-10T02:38:36.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2023-12-15T20:17:52.000Z (almost 2 years ago)
- Last Synced: 2025-01-11T00:12:46.509Z (9 months ago)
- Topics: databinding, samples, x-samples
- Language: Kotlin
- Homepage:
- Size: 364 KB
- Stars: 3
- Watchers: 3
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# DataBindingSample
DataBinding的使用集合
## 关于我
| 公众号 | 掘金 | 知乎 | CSDN | 简书 | 思否 | 哔哩哔哩 | 今日头条
|---------|---------|--------- |---------|---------|---------|---------|---------|
| [我的Android开源之旅](https://t.1yb.co/Irse) | [点我](https://juejin.im/user/598feef55188257d592e56ed/posts) | [点我](https://www.zhihu.com/people/xuexiangjys/posts) | [点我](https://xuexiangjys.blog.csdn.net/) | [点我](https://www.jianshu.com/u/6bf605575337) | [点我](https://segmentfault.com/u/xuexiangjys) | [点我](https://space.bilibili.com/483850585) | [点我](https://img.rruu.net/image/5ff34ff7b02dd)## 准备工作
### 启用
1.DataBinding启用
```groovy
android {
dataBinding {
enabled = true
}
}
```2.ViewBinding启用
```groovy
android {
buildFeatures {
viewBinding true
}
}
```### 快捷方式
在你的布局中找到最外层的布局,将光标放在如图位置。
* Windows请按快捷键 Alt + 回车
* Mac请按快捷键 option + 回车

---
## DataBinding绑定
### 1.数据类型
通常我们在DataBinding中绑定的数据类型是`ViewModel`或者是`AndroidViewModel`,它俩都是生命周期可感知的,唯一的区别是`AndroidViewModel`可以获取到应用的上下文`Application`。
### 2.数据创建
`ViewModel`的创建通常是通过ViewModelProvider进行创建和获取。
```kotlin
ViewModelProvider(this).get(Xxx::class.java)
```而在`ViewModel`中,通常使用`MutableLiveData`作为可变UI响应数据类型。相比较`LiveData`而言,它开放了修改值的接口,下面是一个ViewModel的简单例子:
```kotlin
class RecyclerViewRefreshState(application: Application) : AndroidViewModel(application) {val title = MutableLiveData("RecyclerView的刷新和加载更多演示")
val isLoading = MutableLiveData(false)
val sampleData = MutableLiveData>(arrayListOf())
val loadState = MutableLiveData(LoadState.DEFAULT)
val layoutStatus = MutableLiveData(Status.DEFAULT)
}
```当然了,如果你有一个`LiveData`会随着一个或多个`LiveData`的变化而变化,这个时候你可能就需要使用`MediatorLiveData`,即合并LiveData。
这里我简单利用MediatorLiveData实现一个组合的LiveData--`CombinedLiveData`。
```kotlin
open class CombinedLiveData(vararg liveData: LiveData<*>, block: () -> T) :
MediatorLiveData() {
init {
value = block()
liveData.forEach {
addSource(it) {
val newValue = block()
if (value != newValue) {
value = newValue
}
}
}
}
}fun combineLiveData(
liveData1: LiveData,
liveData2: LiveData,
block: (T1?, T2?) -> R
) = CombinedLiveData(liveData1, liveData2) { block(liveData1.value, liveData2.value) }
```这个时候,我们就可以通过`combineLiveData`方法将两个`LiveData`组合起来,形成一个新的`LiveData`。下面我简单给出一个示例代码:
```kotlin
class CombineLiveDataState : DataBindingState() {
val userName = MutableLiveData("小明")
val userAge = MutableLiveData(20)
val userInfo = combineLiveData(userName, userAge) { name, age ->
"${name}今年${age}岁了!"
}fun onAgeChanged() {
userAge.value = userAge.value?.plus(1)
}
}
```
这里变化了userAge的值后,userInfo也会随着一起变化。### 3.布局绑定
一般我们使用`DataBindingUtil`进行布局绑定操作。绑定操作我们可分为:绑定Activity、绑定Fragment和绑定View。
1. 绑定Activity
使用`DataBindingUtil.setContentView`方法进行绑定。
```kotlin
fun bindActivity(
activity: ComponentActivity,
layoutId: Int
): DataBinding = DataBindingUtil.setContentView(activity, layoutId).apply {
lifecycleOwner = activity
}
```2. 绑定Fragment
使用`DataBindingUtil.inflate`方法进行绑定。
```kotlin
fun bindFragment(
fragment: Fragment,
inflater: LayoutInflater,
layoutId: Int,
parent: ViewGroup? = null,
attachToParent: Boolean = false
): DataBinding = DataBindingUtil.inflate(inflater, layoutId, parent, attachToParent).apply {
lifecycleOwner = fragment.viewLifecycleOwner
}
```3. 绑定View
使用`DataBindingUtil.bind`方法进行绑定。
```kotlin
fun bindView(
view: View,
viewLifecycleOwner: LifecycleOwner,
): DataBinding = DataBindingUtil.bind(view).apply {
lifecycleOwner = viewLifecycleOwner
}
```**【⚠️特别注意事项⚠️️】**
DataBinding绑定的时候,一定要给ViewDataBinding赋值`LifecycleOwner`, 否则`ViewModel`中的`LiveData`发生数据改变后,则不会通知UI组件进行页面更新。
### 4.ViewModel绑定
ViewModel的绑定有两种写法。
* 直接使用`ViewDataBinding.variableId = xxx`直接赋值。
```kotlin
val mainState = ViewModelProvider(this).get(MainState::class.java)
activityMainbinding.state = mainState
```* 使用`ViewDataBinding.setVariable(int variableId, @Nullable Object value)`进行赋值。
```kotlin
val mainState = ViewModelProvider(this).get(MainState::class.java)
binding.setVariable(BR.state, mainState)
```这两者的唯一区别在于,第一种需要知道ViewDataBinding的具体类型,而第二种是ViewDataBinding自身的方法,无需知道ViewDataBinding的具体类型。
一般来说在框架中使用到泛型未知ViewDataBinding具体类型的时候,都会使用第二种方式进行绑定,可以说第二种方式更通用一些。
---
## 基础使用
### 1.点击事件绑定
1.无参响应函数:
```kotlin
fun onIncrement() {
// 方法体
}
``````
android:onClick="@{() -> state.onIncrement()}"
```2.接口变量响应函数
注意,这里变量的类型应该是`View.OnClickListener`接口。
```kotlin
val onClickDecrement = View.OnClickListener {
// 方法体
}
``````
android:onClick="@{state.onClickDecrement}"
```3.有参响应函数
```kotlin
fun onReset(view: View) {
// 方法体
}
``````
// 第一种写法
android:onClick="@{(view) -> state.onReset(view)}"// 第二种写法
android:onClick="@{state::onReset}"
```### 2.@BindingAdapter自定义属性
> 所有注解的功能都是基于XML属性值为DataBinding表达式才生效(即@{})
使用@BindingAdapter进行控件自定义属性绑定的时候,一定要使用 "@{}" 进行赋值,这一点非常重要!!!
1. 顶级函数实现
```kotlin
// Kotlin拓展函数式写法, 推荐使用
@BindingAdapter("customTitle")
fun TextView.setCustomTitle(title: String) {
text = "标题1: $title"
}// 第一个参数必须是view的子类
@BindingAdapter("customTitle1")
fun setCustomTitle1(view: TextView, title: String) {
view.text = "标题2: $title"
}// 多个参数进行绑定,requireAll=true,代表两个参数都设置了才生效,默认是true.
// 如果requireAll为false, 你没有填写的属性值将为null. 所以需要做非空判断.
@BindingAdapter(value = ["customTitle", "customSize"], requireAll = true)
fun TextView.setTextContent(title: String, size: Int) {
text = "标题3: $title"
textSize = size.toFloat()
}
```**【特别注意事项⚠️】**
很多时候,很多新手在写DataBinding的时候,经常会漏掉`"@{}"`,尤其是用数字和Boolean类型的值时。就比如我上面设置的`customSize`属性,类型值是Int型,正确的写法应该是下面这样:
* 正确的写法
```xml
```
* 常见错误的写法
```xml
```
上述错误的写法,运行后编译器会报错`AAPT: error: attribute customSize (aka com.xuexiang.databindingsample:customSize) not found.`。
所以当我们写DataBinding的时候,如果出现`AAPT: error: attribute xxx (aka com.aa.bb:xxx) not found.`,十有八九是你赋值漏掉了`"@{}"`。
2. 单例类+@JvmStatic注解
```kotlin
object TitleAdapter {
@JvmStatic
@BindingAdapter("customTitle2")
fun setCustomTitle2(view: TextView, title: String) {
view.text = "标题4: $title"
}
}
```### 3.@BindingConversion自定义类型转换
作用:在使用DataBinding的时候,对属性值进行转换,以匹配对应的属性。
定义:方法必须为公共静态(public static)方法,且有且只能有1个参数。下面我给一个简单的例子:
1.对于User类,`age`的类型是Int。
```kotlin
data class User(
val name: String,
val gender: String? = "男",
val age: Int = 10,
val phone: String? = "13124765438",
val address: String? = null
)
```2.使用`@BindingAdapter`定义了`age`的类型却是String。
```kotlin
@BindingAdapter(value = ["name", "age"], requireAll = true)
fun TextView.setUserInfo(name: String, age: String) {
text = "${name}今年${age}岁"
}
```3.这时候使用DataBinding的时候,👇的`app:age="@{state.user.age}"`会编译报错,提示类型不匹配。
```xml
```
4.这个时候,我们就可以使用`@BindingConversion`自定义类型转换: Int -> String, 这样👆的代码就不会编译出错了。
```kotlin
@BindingConversion
fun int2string(integer: Int) = integer.toString()
```### 4.@{}中表达式使用
1. 常用运算符
* 算术 + - / * %
* 字符串合并 +
* 逻辑 && ||
* 二元 & | ^
* 一元 + - ! ~
* 移位 >> >>> <<
* 比较 == > < >= <=
* 三元 ?:
* Array 访问 \[\]```xml
```
```xml
```
2. 常用转义字符
* 空格: \
* <小于号: \<
* \>大于号: \>
* &与号: \&```xml
```
3. 资源使用
@string @color @drawable @dimen @array
```xml
```
4. 集合
集合不属于`java.lang*`下, 需要导入全路径。集合使用\[\]进行访问。
```xml
```
```xml```
5. 引用类的静态方法
kotlin中定义静态方法,一定要在方法上加上`@JvmStatic`,否则将无法成功引用。
(1) 定义方法
```kotlin
object AppUtils {@JvmStatic
fun getAppInfo(context: Context?) =
context?.let {
"packageName: ${it.packageName}, \nversionName: ${
it.packageManager.getPackageInfo(
it.packageName,
0
).versionName
}"
}
}
```
(2) 导入方法所在类路径```xml
```
(3) 引用方法
```xml
```
6. 空值合并运算符
空值合并运算符 ?? 会取第一个不为 null 的值作为返回值。
```xml
```
等价于```xml
```
### 5.include 和 ViewStub
在主布局文件中将相应的变量传递给 include 布局,需使用自定义的 bind 命名空间将变量传递给 (include/ViewStub), 从而使两个布局文件之间共享同一个变量。
例如,在include中定义的变量id是:, 那么就使用 app:user="@{state.user}" 来绑定数据,与variable定义的name保持一致。
1. include
```xml
```
```xml
```
如果你想在页面中获取include引用布局的某个控件时,你需要给include设置资源id,然后通过它去访问引用布局中的控件,就以👆的例子为例,如果我想访问布局中的TextView,我们可以这样写:
```kotlin
binding?.includeLayout?.tvTitle?.text = "用户信息"
```**【⚠️特别注意事项⚠️️】**
这里需要注意的是,include标签,如果设置了`layout_width`和`layout_height`这两个属性,那么布局就是由include外层设置的layout属性生效,内层属性不生效。
如果include标签没有设置`layout_width`和`layout_height`这两个属性,那么就是由include引用的布局内层设置的layout属性生效。
举个例子,如果把👆设置的include改成下面这样:
```xml
```
那么`@layout/include_user_info`加载的布局,距离上部的距离就是24dp,而不是16dp。
2. ViewStub
```xml
```
```xml
```
因为ViewStub功能是延迟加载引用的布局,当我们需要让其进行加载的时候,我们需要通过ViewStub的资源id获取到ViewStub,然后进行inflate,示例代码如下:
```kotlin
binding?.userInfo?.viewStub?.inflate()
```---
## 进阶使用
### 简化RecycleView的使用
1.定义一个供绑定的ViewHolder
```kotlin
class BindingViewHolder(val binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root), LifecycleOwner {private val mLifecycle = LifecycleRegistry(this)
fun bindingData(data: T?, variableId: Int = BR.item) {
binding.setVariable(variableId, data)
}init {
mLifecycle.currentState = Lifecycle.State.INITIALIZED
}fun onAttached() {
mLifecycle.currentState = Lifecycle.State.STARTED
}fun onDetached() {
mLifecycle.currentState = Lifecycle.State.RESUMED
}override fun getLifecycle(): Lifecycle = mLifecycle
}
```2.定义一个供绑定的RecyclerView.Adapter
```kotlin
class BindingRecyclerViewAdapter(
@LayoutRes val layoutId: Int,
var dataSource: MutableList
) : RecyclerView.Adapter>() {override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val binding = DataBindingUtil.inflate(
layoutInflater,
layoutId,
parent,
false
)
val holder = BindingViewHolder(binding)
binding.lifecycleOwner = holder
return holder
}override fun onBindViewHolder(holder: BindingViewHolder, position: Int) {
holder.setDataBindingVariables(dataSource.getOrNull(position))
holder.itemView.tag = position
if (holder.binding.hasPendingBindings()) holder.binding.executePendingBindings()
}override fun getItemCount() = dataSource.size
@SuppressLint("NotifyDataSetChanged")
fun refresh(data: List) {
if (data.isNotEmpty()) {
dataSource = data.toMutableList()
notifyDataSetChanged()
}
}@SuppressLint("NotifyDataSetChanged")
fun loadMore(data: List) {
if (data.isNotEmpty()) {
dataSource.addAll(data)
notifyDataSetChanged()
}
}override fun onViewAttachedToWindow(holder: BindingViewHolder) {
holder.onAttached()
}override fun onViewDetachedFromWindow(holder: BindingViewHolder) {
holder.onDetached()
}override fun onViewRecycled(holder: BindingViewHolder) {
holder.binding.lifecycleOwner = null
super.onViewRecycled(holder)
}
}
```3.使用@BindingAdapter自定义绑定方法
```kotlin
@BindingAdapter(
value = ["data", "itemLayout", "loadState"],
requireAll = false
)
fun RecyclerView.setBindingRecyclerViewAdapter(
data: List?,
@LayoutRes layoutId: Int?,
loadState: LoadState? = LoadState.DEFAULT,
) {
requireNotNull(data) { "app:data argument cannot be null!" }
requireNotNull(layoutId) { "app:itemLayout argument cannot be null!" }if (adapter == null) {
adapter = BindingRecyclerViewAdapter(layoutId, data.toMutableList())
layoutManager = XLinearLayoutManager(context)
} else {
@Suppress("UNCHECKED_CAST")
(adapter as? BindingRecyclerViewAdapter)?.run {
when (loadState) {
LoadState.REFRESH -> refresh(data, selectedPosition)
LoadState.LOAD_MORE -> loadMore(data)
else -> {}
}
}
}
}
```4.在xml中进行数据绑定
```xml
```
5.在ViewModel中设置数据
```kotlin
class RecyclerViewBasicState(application: Application) : DataBindingPageState(application) {
override fun initTitle() = "RecycleView的基础使用演示"
val sampleData = MutableLiveData(getDemoData(application))
fun getDemoData(context: Context, from: Int = 1, to: Int = 40): List {
// 模拟数据加载
val list = mutableListOf()
for (index in from..to) {
list.add(
SimpleItem(
context.getString(R.string.item_example_number_title, index),
context.getString(R.string.item_example_number_subtitle, index)
)
)
}
return list
}
}
```这样,有了这样一套绑定体系后,后面我们再需要使用到RecyclerView的时候,就只需要4和5步就行了,1-3步都是可重复使用的。
### RecycleView的进阶使用
我们除了可以简单地使用DataBinding去加载RecyclerView的数据,我们还可以拓展其他一些操作来增强对RecyclerView的使用。
1.分割线的颜色和高度
```kotlin
@BindingAdapter(
value = ["data", "itemLayout", "loadState", "dividerHeight", "dividerColor"],
requireAll = false
)
fun RecyclerView.setBindingRecyclerViewAdapter(
data: List?,
@LayoutRes layoutId: Int?,
loadState: LoadState? = LoadState.DEFAULT,
dividerHeight: Float? = null,
@ColorInt dividerColor: Int? = null,
) {
requireNotNull(data) { "app:data argument cannot be null!" }
requireNotNull(layoutId) { "app:itemLayout argument cannot be null!" }if (adapter == null) {
adapter = BindingRecyclerViewAdapter(layoutId, data.toMutableList())
layoutManager = XLinearLayoutManager(context)
setDividerStyle(dividerHeight, dividerColor)
} else {
@Suppress("UNCHECKED_CAST")
(adapter as? BindingRecyclerViewAdapter)?.run {
when (loadState) {
LoadState.REFRESH -> refresh(data, selectedPosition)
LoadState.LOAD_MORE -> loadMore(data)
else -> {}
}
}
}
}fun RecyclerView.setDividerStyle(
dividerHeight: Float? = null,
@ColorInt dividerColor: Int? = null
) {
val divider = DividerItemDecoration(context, LinearLayoutManager.VERTICAL)
dividerHeight?.let {
divider.dividerHeight = it.roundToInt()
}
dividerColor?.let {
divider.dividerColor = it
}
addItemDecoration(divider)
}```
2.事件监听
(1) 定义监听接口
```kotlin
/**
* 列表条目点击监听
*/
interface OnItemClickListener {
/**
* 条目点击
*
* @param itemView 条目
* @param item 数据
* @param position 索引
*/
fun onItemClick(itemView: View?, item: T?, position: Int)
}/**
* 列表条目长按监听
*/
interface OnItemLongClickListener {
/**
* 条目长按
*
* @param itemView 条目
* @param item 数据
* @param position 索引
*/
fun onItemLongClick(itemView: View?, item: T?, position: Int) : Boolean = true
}
```(2) Adapter设置监听
```kotlin
class BindingRecyclerViewAdapter(
@LayoutRes val layoutId: Int,
var dataSource: MutableList,
var onItemClickListener: OnItemClickListener?,
var onItemLongClickListener: OnItemLongClickListener?,
) : RecyclerView.Adapter>() {override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val holder = createViewHolder(layoutInflater, parent, viewType)
initViewHolder(holder)
return holder
}private fun initViewHolder(holder: BindingViewHolder) {
onItemClickListener?.run {
holder.itemView.setOnClickListener {
val position = holder.itemView.tag as Int
onItemClick(it, dataSource.getOrNull(position), position)
}
}
onItemLongClickListener?.run {
holder.itemView.setOnLongClickListener {
val position = holder.itemView.tag as Int
onItemLongClick(it, dataSource.getOrNull(position), position)
}
}
}override fun onBindViewHolder(holder: BindingViewHolder, position: Int) {
holder.bindingData(dataSource.getOrNull(position))
holder.itemView.tag = position
if (holder.binding.hasPendingBindings()) holder.binding.executePendingBindings()
}
}
```(3) 使用@BindingAdapter自定义绑定方法
```kotlin
@BindingAdapter(
value = ["data", "itemLayout", "loadState", "dividerHeight", "dividerColor", "itemClick", "itemLongClick"],
requireAll = false
)
fun RecyclerView.setBindingRecyclerViewAdapter(
data: List?,
@LayoutRes layoutId: Int?,
loadState: LoadState? = LoadState.DEFAULT,
dividerHeight: Float? = null,
@ColorInt dividerColor: Int? = null,
onItemClickListener: OnItemClickListener? = null,
onItemLongClickListener: OnItemLongClickListener? = null,
) {
requireNotNull(data) { "app:data argument cannot be null!" }
require(layoutId != null || itemViewParser != null) { "app:itemLayout and app:itemViewParser argument need a parameter that is not null!" }if (adapter == null) {
adapter = BindingRecyclerViewAdapter(
layoutId,
data.toMutableList(),
onItemClickListener,
onItemLongClickListener
)
layoutManager = XLinearLayoutManager(context)
setDividerStyle(dividerHeight, dividerColor)
} else {
@Suppress("UNCHECKED_CAST")
(adapter as? BindingRecyclerViewAdapter)?.run {
when (loadState) {
LoadState.REFRESH -> refresh(data, selectedPosition)
LoadState.LOAD_MORE -> loadMore(data)
else -> {}
}
}
}
}
```3.多布局类型加载
(1) 定义布局解析器接口
```kotlin
interface ItemViewParser {
fun getItemViewType(position: Int): Int
fun getItemLayoutId(viewType: Int): Int
}
```(2) 增加布局解析器默认实现
```kotlin
class DefaultItemViewParser(@LayoutRes val layoutId: Int): ItemViewParser {override fun getItemViewType(position: Int) = 0
override fun getItemLayoutId(viewType: Int) = layoutId
}
```(3) 重写Adapter的`onCreateViewHolder`方法和`getItemViewType`方法
```kotlin
class BindingRecyclerViewAdapter(
private val itemViewParser: ItemViewParser,
var dataSource: MutableList,
var onItemClickListener: OnItemClickListener?,
var onItemLongClickListener: OnItemLongClickListener?,
) : RecyclerView.Adapter>() {override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val holder = createViewHolder(layoutInflater, parent, viewType)
initViewHolder(holder)
return holder
}private fun createViewHolder(
layoutInflater: LayoutInflater,
parent: ViewGroup,
viewType: Int
): BindingViewHolder {
val binding = DataBindingUtil.inflate(
layoutInflater,
itemViewParser.getItemLayoutId(viewType),
parent,
false
)
val holder = BindingViewHolder(binding)
binding.lifecycleOwner = holder
return holder
}override fun getItemViewType(position: Int): Int {
return itemViewParser.getItemViewType(position)
}
}
```(4) 使用@BindingAdapter自定义绑定方法
```kotlin
@BindingAdapter(
value = ["data", "itemLayout", "itemViewParser", "loadState", "dividerHeight", "dividerColor", "itemClick", "itemLongClick"],
requireAll = false
)
fun RecyclerView.setBindingRecyclerViewAdapter(
data: List?,
@LayoutRes layoutId: Int?,
itemViewParser: ItemViewParser?,
loadState: LoadState? = LoadState.DEFAULT,
dividerHeight: Float? = null,
@ColorInt dividerColor: Int? = null,
onItemClickListener: OnItemClickListener? = null,
onItemLongClickListener: OnItemLongClickListener? = null,
) {
requireNotNull(data) { "app:data argument cannot be null!" }
require(layoutId != null || itemViewParser != null) { "app:itemLayout and app:itemViewParser argument need a parameter that is not null!" }if (adapter == null) {
adapter = BindingRecyclerViewAdapter(
itemViewParser ?: DefaultItemViewParser(layoutId!!),
data.toMutableList(),
onItemClickListener,
onItemLongClickListener
)
layoutManager = XLinearLayoutManager(context)
setDividerStyle(dividerHeight, dividerColor)
} else {
@Suppress("UNCHECKED_CAST")
(adapter as? BindingRecyclerViewAdapter)?.run {
when (loadState) {
LoadState.REFRESH -> refresh(data, selectedPosition)
LoadState.LOAD_MORE -> loadMore(data)
else -> {}
}
}
}
}
```4.刷新和加载更多
这里为了简单,我使用了开源的SmartRefreshLayout组件实现上拉刷新,下拉加载。
(1)使用@BindingAdapter自定义绑定方法
```kotlin
@BindingAdapter(
value = ["refreshListener", "loadMoreListener"],
requireAll = false
)
fun SmartRefreshLayout.setRefreshLayoutListener(
refreshListener: OnRefreshListener?,
loadMoreListener: OnLoadMoreListener?
) {
setOnRefreshListener(refreshListener)
setOnLoadMoreListener(loadMoreListener)
}
```(2)在xml中进行数据绑定
```xml
```
(3)在ViewModel中设置数据
```kotlin
class RecyclerViewRefreshState(application: Application) : DataBindingPageState(application) {
val sampleData = MutableLiveData>(arrayListOf())
val loadState = MutableLiveData(LoadState.DEFAULT)
var pageIndex = 0
val refreshListener = OnRefreshListener { refreshLayout ->
// 延迟1000ms模拟网络请求延时
refreshLayout.layout.postDelayed({
pageIndex = 0
loadState.value = LoadState.REFRESH
sampleData.value = sampleGetData(application)
refreshLayout.finishRefresh()
refreshLayout.resetNoMoreData()
}, 1000)
}val loadMoreListener = OnLoadMoreListener { refreshLayout ->
refreshLayout.layout.postDelayed({
pageIndex += 1
loadState.value = LoadState.LOAD_MORE
sampleData.value = sampleGetData(application)
if (pageIndex >= 3) { // 模拟只能加载更多3页,即总共4页的数据
refreshLayout.finishLoadMoreWithNoMoreData()
} else {
refreshLayout.finishLoadMore()
}
}, 1000)
}/**
* 模拟获取数据
*/
private fun sampleGetData(context: Context) =
getDemoData(context, pageIndex * PAGE_SIZE + 1, PAGE_SIZE * (pageIndex + 1))
}
```## 特别感谢
* [Android 安卓DataBinding详解(超详细)](https://blog.csdn.net/qq_40881680/article/details/102240892)
* [DataBinding最全使用说明](https://juejin.cn/post/6844903549223059463)
* [Android DataBinding 从入门到进阶](https://juejin.cn/post/6844903609079971854)## 如果觉得项目还不错,可以考虑打赏一波
> 你的打赏是我维护的动力,我将会列出所有打赏人员的清单在下方作为凭证,打赏前请留下打赏项目的备注!

## 联系方式
> 更多资讯内容,欢迎扫描关注我的个人微信公众号:【我的Android开源之旅】
