Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
}
like image 761
hidro Avatar asked Dec 29 '15 16:12

hidro


People also ask

Which is the correct way to reference bound data in the XML layout?

Layout Binding expressions Expressions in the XML layout files are assigned to a value of the attribute properties using the “ @{} " syntax. We just need to use the basic syntax @{} in an assignment expression.

How do I convert layout to Data Binding layout?

To convert your XML layouts into the Data Binding layout, follow the below steps: Declare a <layout> tag, which will wrap your existing layout file at the root level. Declare variables under the <data> tag, which will go under the <layout> tag. Declare necessary expressions to bind data inside the view elements.

Can I use both Data Binding and view binding?

View binding doesn't support layout variables or layout expressions, so it can't be used to declare dynamic UI content straight from XML layout files. View binding doesn't support two-way data binding.

What is 2 way Data Binding in Android?

Stay organized with collections Save and categorize content based on your preferences. The @={} notation, which importantly includes the "=" sign, receives data changes to the property and listen to user updates at the same time. // Avoids infinite loops.


2 Answers

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
}
like image 44
Eugen Pechanec Avatar answered Oct 11 '22 08:10

Eugen Pechanec


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..

like image 118
Wilson S Avatar answered Oct 11 '22 06:10

Wilson S