26

I am trying out the new Android Databinding Library and I wanted to set the background color of ToolBar using a binding. By default the color should be colorPrimary (from the theme).

Before I was using DataBinding, my toolBar looked like

 <android.support.v7.widget.Toolbar
        android:id="@+id/mainToolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        />

After adding a binding, I wanted to set its background to colorPrimary if no color is bound - I'm using ternary operator for this (as mentioned in the guide) - but it causes an error, as theme attributes also have a "?" operator before their names. The compiler thinks I'm starting a new ternary operation.

<data>
    <variable name="toolBarBackgroundColor" type="int"/>
</data>
...
<android.support.v7.widget.Toolbar
        android:id="@+id/mainToolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@{toolBarBackgroundColor!=0? toolBarBackgroundColor: ?attr/colorPrimary }"
        />

So is there a way I can access theme attributes inside a binding operation? Thanks!

Edit

I know I can get the colorPrimary attribute programmatically and bind it through java code. But I'm just wondering if there's an Xml-based solution for this or not.

sudo_rizwan
  • 584
  • 5
  • 10
  • 4
    Sorry, we don't have support for theme attributes yet. As a workaround, you can define it as a color resource value and use it in the ternary via @color/colorPrimary . – yigit Jul 06 '15 at 07:28
  • Oh Ok. I'll try the resource value workaround. Thanks – sudo_rizwan Jul 06 '15 at 11:19
  • 1
    Did it worked? using it like `?android:attr/textColorPrimary` – subhash Oct 05 '15 at 12:31
  • 1
    @yigit any updates on supporting theme attributes? – Oleg Osipenko Jul 22 '16 at 15:02
  • 1
    no, and it is very unlikely to happen. First of all, most views only parse these in their constructor. There is no dynamic `setStyle` method on the View class. A solution could be to parse app styles, figure out what values are set then find their setters on the view but that is not rock solid since styles extend from device styles which can be customized by the manifacturers. – yigit Jul 22 '16 at 15:09

4 Answers4

3

The answer is a bit late, but maybe it helps someone.

For accessing theme attributes in data binding, you can use this:

(imagine that clickable is Boolean variable)

android:background="@{clickable ? android.R.attr.selectableItemBackground : android.R.color.transparent}"

No additional binding adapters or another things needed.

tikhonos
  • 592
  • 4
  • 11
  • 4
    This does not work properly. I voted without checking completely. When `clickable is false` seems works correctly, but when `clickable is true` does not set `selectableItemBackground` as background, because in my case it is `drawable` and in generated code passed to `android.databinding.adapters.Converters.convertColorToDrawable` as `color` – Berdimurat Masaliev Jul 04 '18 at 06:10
  • This doesn't work in 2019 either. Is there a solution besides not using ternaries in XML? – Zeek Aran Oct 10 '19 at 16:07
  • Both terms in a ternary expression need to have the same type; you can't return two different types from a databinding expression (in this case, a drawable and a color). However, you can use a static method to convert the color to a ColorDrawable, e.g. import `androidx.databinding.adapters.Converters` and use `Converters.convertColorToDrawable(toolBarBackgroundColor)` in the ternary expression. Or, use a value passed as a `ColorDrawable` instead. Or, move the logic into a data binding adapter method, so the logic is in a location easier to debug. – Lorne Laliberte Mar 12 '20 at 16:12
2

Finding a way using data-binding? Here is what I have done with test. First, create a custom binding adapter method:

@BindingAdapter({"app:customPrimaryBackground"})
public static void setCustomPrimaryBackground(View v, int resId) {
    TypedValue typedValue = new TypedValue();
    Context context = v.getContext();
    if (resId == 0) {
        context.getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
        v.setBackgroundResource(typedValue.resourceId);
    } else {
        // Check the given resource ID is a color or drawable
        context.getResources().getValue(resId, typedValue, true);
        Drawable drawable;
        if (typedValue.type >= TypedValue.TYPE_FIRST_COLOR_INT && typedValue.type <= TypedValue.TYPE_LAST_COLOR_INT) {
            // It's a color
            drawable = new ColorDrawable(typedValue.data);
        } else {
            drawable = ContextCompat.getDrawable(context, resId);
        }

        v.setBackground(drawable);
    }
}

Second, your binding xml layout:

<data>
    <variable name="toolBarBackgroundColor" type="int"/>
</data>
...
<android.support.v7.widget.Toolbar
        android:id="@+id/mainToolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:customPrimaryBackground="@{toolBarBackgroundColor}"
/>
maohieng
  • 1,646
  • 1
  • 19
  • 26
2

If the question is still actual for someone, this is the example how to use custom and android attributes app:textColorAttr="@{error ? com.example.R.attr.textColorError : android.R.attr.textColor}", where textColorAttr implemented using BindingAdapter, error is Boolean and com.example is your package name

2

I found another solution without custom attributes and binding adapters. The idea is to place an invisible View with android:background and android:foreground attributes in XML markup and use these attributes in a binding expression.

<data>
    <variable name="toolBarBackgroundColor" type="int"/>
</data>

...

<android.support.v7.widget.Toolbar
    android:id="@+id/mainToolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="@{toolBarBackgroundColor != 0 ? helperView.getBackground() : helperView.getForeground() }"
    />

<View
    android:id="@+id/helperView"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:background="@{toolBarBackgroundColor}"
    android:foreground="?attr/colorPrimary"
    android:visibility="gone"
    />
Vadim Aushev
  • 21
  • 1
  • 2