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
}
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.
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.
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.
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.
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.
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).
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
}
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..
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With