Использование ресурсов атрибутов (? Attr/) в привязке компоновки?

В настоящее время привязка данных в Android поддерживает следующие справочные ресурсы (согласно руководству по привязке данных): @array, @color, @int, @dimen, @string..., который даст ссылочные значения в качестве аргументов в статическом методе @BindingAdapter.

Например:

макет /web _view.xml

<WebView
    app:htmlTextColor="@{@color/colorText}"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Bindings.java

@BindingAdapter({"bind:htmlTextColor"})
public static void setHtml(WebView webView, int textColor) {
    // binding logic
}

Но с темами и стилями, чаще всего я использую ресурс атрибута, например. ?android:attr/textColorPrimary, чем a @color. Для таких случаев, как бы выглядел синтаксис привязки "@{}"? В настоящее время это то, как я заставляю его работать, но, может быть, есть лучший способ?

макет /web _view.xml

<WebView
    app:htmlTextColor="@{android.R.attr.textColorPrimary}"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Bindings.java

@BindingAdapter({"bind:htmlTextColor"})
public static void setHtml(WebView webView, int textColorAttr) {
    // binding logic
}

Ответы

Ответ 1

Если @{android.R.attr.textColorPrimary} разрешено значение android.R.attr.textColorPrimary в Java, все, что вам нужно сделать, это разрешить это для цвета.

В этом есть немного настроек.

ContextUtils.java

Следующий метод разрешает поставку attr темы context и необязательный style для цвета. Возвращается к цвету fallback, если есть ошибка.

@ColorInt
public static int resolveColor(final Context context, @StyleRes final int style, @AttrRes final int attr, @ColorInt final int fallback) {
    final TypedArray ta = obtainTypedArray(context, style, attr);
    try {
        return ta.getColor(0, fallback);
    } finally {
        ta.recycle()
    }
}

@ColorInt
public static int resolveColor(final Context context, @AttrRes final int attr, @ColorInt final int fallback) {
    return resolveColor(context, 0, attr, fallback);
}

Полезные методы, помогающие эффективно достичь вышеуказанной цели.

private static TypedArray obtainTypedArray(final Context context, @StyleRes final int style, @AttrRes final int attr): TypedArray {
    final int[] tempArray = getTempArray();
    tempArray[0] = attr;
    return context.obtainStyledAttributes(style, tempArray);
}

private static final ThreadLocal<int[]> TEMP_ARRAY = new ThreadLocal<>();

private static final int[] getTempArray() {
    int[] tempArray = TEMP_ARRAY.get();
    if (tempArray == null) {
        tempArray = int[1];
        TEMP_ARRAY.set(tempArray);
    }
    return tempArray;
}

Более сложный код, доступный в my android-commons library (эта часть написана в Kotlin, возьмите то, что вам нужно).

Bindings.java

Здесь, как его использовать:

@BindingAdapter({"bind:htmlTextColor"})
public static void setHtml(final WebView webView, @AttrRes final int textColorAttr) {
    final Context context = webView.getContext();
    final int textColor = ContextUtils.resolveColor(context, textColorAttr, Color.BLACK);

    // binding logic
}

Ответ 2

Похоже, что темы в настоящее время не поддерживаются для использования в выражениях макета с привязкой данных, как объясняется @yigit в комментариях для вопроса здесь.

Ответ 3

Используйте BindingAdapter

BindingAdapter позволяет вам манипулировать и выполнять более сложную логику с вашими данными, прежде чем применять их к представлению. Чтобы использовать BindingAdapter, сначала создайте в своем коде статический метод, который привязан либо к стандартному атрибуту Android, либо к пользовательскому.

Я создаю пользовательский атрибут здесь с именем characterBackground:

@BindingAdapter({"characterBackground"})
public static void characterBackground(TextView textView, AdventureTimeCharacters character) {
     textView.setBackgroundColor(ContextCompat.getColor(textView.getContext(), character.getColour()));
}

Затем вы можете использовать этот BindingAdapter в TextView:

app:characterBackground="@{character}"

Не забудьте добавить пространство имен приложения! Android Studio может добавить это для вас. Просто введите appNs, и он будет автоматически заполнен.

Это решение работает, но слишком сложно. И вы сказали, что привязка данных легко..