Android Привязка данных - Как переопределить значение по умолчанию @BindingMethods для сгенерированного класса макета? - PullRequest
0 голосов
/ 29 февраля 2020

Я столкнулся с несколькими проблемами при использовании настраиваемого адаптера привязки для CardView:

Вот мои файлы:

component_empty_state. xml

<?xml version="1.0" encoding="utf-8"?>
<layout>

    <data>

        <variable
            name="radiusId"
            type="Integer" />
    </data>

    <android.support.v7.widget.CardView 
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/cardviewRoot"
        app:customCornerRadius="@{radiusId ?? @dimen/default_radius}"
<!-- or -->
        app:cardCornerRadius="@{radiusId ?? @dimen/default_radius}"
>

            <!-- omitted -->

    </android.support.v7.widget.CardView>

</layout>

CustomBindingAdapter.kt

  1. Это работает (сгенерированный макет - ComponentEmptyStateBindingImpl вызовет этот метод)
fun dp(dimen: Int) resources.getDimension(dimen).toInt() / resources.displayMetrics.density

@BindingAdapter("customCornerRadius")
fun CardView.setCardCornerRadius(@DimenRes dimenId: Int) {
    this.radius = dp(dimenId)
}
Это не работает (сгенерированный макет - ComponentEmptyStateBindingImpl будет вызывать по умолчанию CardView#setRadius(float) вместо)
@BindingAdapter("cardCornerRadius")
fun CardView.setCardCornerRadius(@DimenRes dimenId: Int) {
    this.radius = dp(dimenId)
}

Результат сгенерированного макета component_empty_state.xml ComponentEmptyStateBindingImpl. java

  1. это результат при использовании первого подхода с использованием пользовательских атрибутов (customCornerRadius)
// omitted
        if ((dirtyFlags & 0xa0L) != 0) {
            // api target 1

            com.package.utils.bindingadapter.CustomBindingAdapterKt.setCardCornerRadius(this.cardviewRoot, cardCornerRadiusJavaLangObjectNullCardviewRootAndroidDefaultRadiusCardCornerRadius);
        }
// omitted
будет использовать по умолчанию CardView#setRadius(float) вместо @BindingAdapter внутри CustomBindingAdapter.kt
// omitted
        if ((dirtyFlags & 0xa0L) != 0) {
            // api target 1

            this.cardviewRoot.setRadius(cardCornerRadiusJavaLangObjectNullCardviewRootAndroidDefaultRadiusCardCornerRadius);
        }
// omitted

Через некоторое время после отладки я обнаружил этот класс:

package android.databinding.adapters;

@BindingMethods({
        @BindingMethod(type = android.support.v7.widget.CardView.class, 
                       attribute = "cardCornerRadius", method = "setRadius"),
// omitted...
})
public class CardViewBindingAdapter {
    // omitted
}

И читая официальные документы здесь & здесь объясняя различия @BindingAdapter и @BindingMethod

Затем я сделал вывод, что он до сих пор не поддерживается переопределить значение по умолчанию @BindingMethods внутри CardViewBindingAdapter?

Как указано в официальных android документах здесь в отношении android & пространств имен custom / app

  1. Если мы хотим переопределить android:text, то это должно быть определено явно:
@BindingAdapter("android:text")
app:srcCompat нет необходимости определять первый параметр app, например:
@BindingAdapter("srcCompat")

// able to be called like this in xml:
xmlns:custom_binding="http://schemas.android.com/apk/res-auto"
custom_binding:srcCompat="@{data}"

Мой текущий подход:

  1. Использовать первый метод в CustomBindingAdapter.kt с атрибутом пользовательского установщика app:customCornerRadius)
        // 01. will using custom @BindingAdapter defined
        app:customCornerRadius="@{radiusId ?? @dimen/default_radius}"
binding.apply {
  radiusId = R.dimen.custom_radius // this is works
}
Не создавайте никаких пользовательских методов, используя @BindingAdapter для атрибутов CardView xmls, но используйте прямое преобразование, например:
        // 02. will using default `CardView#setRadius(float)` instead
        app:cardCornerRadius="@{radiusId ?? @dimen/default_radius}"
binding.apply {
  radiusId = root.getResources().getDimension(R.dimen.custom_radius) // this is works
}
...