hidro
hidro

Reputation: 12521

Using attribute resources (?attr/) in layout binding?

Data binding in Android currently seems to support the following reference resources (according to data binding guide): @array, @color, @int, @dimen, @string... which will give referenced values as arguments in static @BindingAdapter method.

For example:

layout/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
}

But with themes and styles, it's more often that I use an attribute resource, e.g. ?android:attr/textColorPrimary than a @color reference. For such cases, how would the binding "@{}" syntax look like? Currently this is how I make it work, but maybe there is a better way?

layout/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
}

Upvotes: 36

Views: 8860

Answers (3)

Eugen Pechanec
Eugen Pechanec

Reputation: 38223

If @{android.R.attr.textColorPrimary} resolves to the value of android.R.attr.textColorPrimary in Java, all you need to do is resolve that to a color.

There's a bit of a setup going into this.

ContextUtils.java

The following method resolves supplied attr of context's theme and optional style to a color. Falls back to fallback color if there's an error.

@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);
}

Utility methods helping to achieve the above goal efficiently.

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;
}

More complex code available in my android-commons library (here and here).

Bindings.java

Here's how to use it:

@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
}

Upvotes: 2

Wilson S
Wilson S

Reputation: 11

Use a BindingAdapter

A BindingAdapter lets you manipulate and do a bit more involved logic on your data before applying it to the View. To use a BindingAdapter, first create a static method in your code that is bound to either a standard Android attribute or a custom one.

I create a custom attribute here called characterBackground:

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

You can then use this BindingAdapter in the TextView:

app:characterBackground="@{character}"

Do not forget to add the app namespace! Android Studio can add this for you. Just type in appNs and it will autocomplete.

This solution works, but is a bit too involved. And you said data binding is easy..

Upvotes: 1

SeptimusX75
SeptimusX75

Reputation: 2195

It appears that themes are currently not supported for use in layout expressions with databinding as is explained by @yigit in the comments for the question here.

Upvotes: 0

Related Questions