如何使用数据绑定动态设置app:icon?

How to set app:icon dynamically with data binding?

我有这个XML:

<Button
     android:id="@+id/btn_default"
     app:icon="@{model.actionBarData.myDynamicIcon}" />

我在模型的 actionBarData 中有这个方法和 LiveData 以编程方式设置图标:

private var _myDynamicIcon = MutableLiveData<Int>()
val myDynamicIcon: LiveData<Int>
    get() = _myDynamicIcon


// Called by some logic in my app

fun setMyDynamicIcon() {
    _myDynamicIcon.value = when (status) {
        status.STATUS1 -> R.drawable.icon1
        status.STATUS2 -> R.drawable.icon2
        status.STATUS3 -> R.drawable.icon3
    }
}

我希望在调用 setMyDynamicIcon 时更改图标。但是我得到错误:

Cannot find a setter for <android.widget.Button app:icon> that accepts parameter type 'androidx.lifecycle.LiveData<java.lang.Integer>'

我还尝试在 myDynamicIcon 中存储一个 Drawable 对象,这也不起作用(同样的错误,但类型为 Drawable)。

如何通过数据绑定设置app:icon

你可以使用 Binding Adapters,你只需要稍微改变你的 setMyDynamicIcon() 实现(即,使其成为绑定适配器方法),其他代码差不多 copy/paste来自提供的 link,它会正常工作。

谢谢@generatedAcc.x09218。使用绑定适配器的最终代码:

XML:

 <Button
       android:id="@+id/btn_default"
       app:dynamicIcon="@{model.actionBarData.status}" />

适配器:

@BindingAdapter("dynamicIcon")
fun View.setDynamicIcon(status: Status?) {
    status?.let {
        val iconResource = when(status) {
            Status.STATUS1 -> R.drawable.ic_1
            Status.STATUS2 -> R.drawable.ic_2
            Status.STATUS3 -> R.drawable.ic_3
        }

        (this as MaterialButton).setIconResource(iconResource)
    }
}

实时数据:

    private var _status = MutableLiveData<Status>()
    val status: LiveData<Status>
        get() = _status

    fun setStatus(status: Status) {
        _status.value = status
    }

图标在 setStatus 调用时发生变化。

有通用的BindingAdapter

@BindingAdapter("dynamicIcon")
fun setDynamicIcon(button: MaterialButton, @DrawableRes resourceId: Int) =
    button.setIconResource(resourceId)

使用示例

app:dynamicIcon="@{viewModel.iconDepositButton(item)}"

奖金

@BindingAdapter("dynamicIconGravity")
fun setIconGravity(button: MaterialButton, @MaterialButton.IconGravity iconGravity: Int) {
    button.iconGravity = iconGravity
}