java - Как установить атрибут enum по значению вместо имени в Android Layout?




android-layout enums (2)

Я не могу установить перечисление по значению, но только по имени

Это не совсем верно. Вы не сможете установить значение с помощью DataBinding даже по имени, дело в том, что значение атрибута, определенного в xml, передается в View через конструктор. View может иметь как атрибут, так и сеттер, но это не всегда так. Например, если вы устанавливаете значение для android:text для TextView , это значение устанавливается в com.android.internal.R.styleable.TextView_text которое затем извлекается из AttributeSet в конструкторе. Если вы используете DataBinding, вызывается setText() , но это две совершенно разные вещи, функция та же, но они не связаны в коде.

Учитывая, что вы не можете изменить MyInnerView и что нет установщика, который вы можете вызвать для myAttr , ваш единственный вариант - передать его через конструктор. Привязка данных просто невозможна, даже с BinderAdapter вы не сможете установить значение в AttributeSet потому что представление уже создано в этой точке.

Вариант 1 - темы

Определить новый атрибут

<attr name="MyInnerViewAttrValue" format="integer" />

Затем разрешите этот атрибут стилем, например, вы могли бы иметь

<style name="AppTheme.Foo">
    <item name="MyInnerViewAttrValue">0</item>
</style>

<style name="AppTheme.Bar">
    <item name="MyInnerViewAttrValue">1</item>
</style>

Установите его в макете XML

<com.example.MyInnerView
    ...
    app:myAttr="?attr/MyInnerViewAttrValue" />

А затем вызовите setTheme(int) в Activity перед созданием экземпляров представлений.

Вариант 2 - пользовательский BindingAdapter

Если вы хотите установить значение DataBinding (потому что у вас есть установщик или вы хотите взломать MyInnerView с отражением), вам необходимо создать, например, пользовательский BindingAdapter.

@BindingAdapter("myAttrValue")
public static void setMyAttr(MyInnerView myInnerView, int value) {
    switch (value) {
        case 0:
            myInnerView.foo();
            break;
        default:
            myInnerView.bar();
    }
}

Тогда в макете XML

<com.example.lelloman.dummy.MyInnerView
    ...
    myAttrValue="@{model.attr}" />

И дать значение int из вашей ViewModel

public class MyInnerViewModel {

    public int getAttr() {
        return 1234;
    }
}

У меня есть один пользовательский вид, содержащий другой. Иерархия:

MyOuterView
->MyInnerView

MyInnerView имеет атрибут enum, например:

<attr name="myAttr" format="enum">
    <enum name="foo" value="0"/>
    <enum name="bar" value="1"/>
</attr>

Таким образом, я могу создать экземпляр компонента в MyOuterView XML, например:

<com.example.MyInnerView
....
app:myAttr="foo"/>

Который работает, конечно. MyOuterView предлагает аргумент для самой настройки. Основываясь на этом аргументе, я хочу установить аргумент MyInnerView .

Желаемое поведение заключается в том, что я могу работать с привязкой данных, как:

<com.example.MyInnerView
....
app:myAttr="@{data.getMyAttr()}"/>

где getMyAttr() выглядит так:

public int getMyAttr() {
    return myAttr; // returns 0 or 1
}

Результатом является проблема компиляции.

**** / ошибка привязки данных **** msg: не удается найти установщик для атрибута app: myAttr с типом параметра int в com.example.MyInnerView

Очевидно, что я не могу установить перечисление по значению, но только по имени. Любая идея помимо создания MyInnerView программно? Обратите внимание, что я не могу изменить MyInnerView .


К сожалению, вы можете использовать имя атрибута, например app:myAttr="@{...}" только если для этого есть установщик, и этот установщик сопоставлен с именем атрибута или может быть разрешен по его имени. В вашем случае, если этот атрибут используется только в конструкторе View, а представление не имеет какого-либо открытого метода для изменения этого - у вас все еще есть несколько возможных решений: - расширить View и реализовать логику, чтобы настроить представление так, как это делает атрибут (если возможно) - сделайте BindingAdapter и используйте Reflection (если возможно). - создайте свой собственный вид путем копирования и вставки)





android-databinding