54

While using the new data binding api, I found that you can't bind to the "style" attribute. Compiler complains that it can't find the style. However, if I simply set the style as is, it'll find it just fine. For example:

doesn't work:

style="@{TextUtils.isEmpty(row.getSubtitle()) ? @style/SubTitle : @style/Title}"

works:

style="@style/SubTitle"

Error:

Error:Execution failed for task ':app:compileDebugJavaWithJavac'.

java.lang.RuntimeException: Found data binding errors. ****/ data binding error ****msg:Identifiers must have user defined types from the XML file. SubTitle is missing it file:/~/test/app/src/main/res/layout/row.xml loc:48:71 - 48:78 ****\ data binding error ****

Jonik
  • 80,077
  • 70
  • 264
  • 372
worked
  • 5,762
  • 5
  • 54
  • 79

4 Answers4

49

The data binding unfortunately is not supported for styles: https://code.google.com/p/android-developer-preview/issues/detail?id=2613

bwhite
  • 2,643
  • 1
  • 18
  • 8
  • yea sorry. As mentioned in the ticket, this is a limitation of the framework that DataBinding cannot work around. – yigit Nov 13 '15 at 20:48
  • 29
    That's a real bummer. I was hoping to use conditional styles with data binding. – Vas Jun 20 '16 at 05:52
14

Although @bwhite is correct, there may be workarounds you can do. It depends what you need to conditionally change. For instance, if you want to change the font based on the condition (which I needed to do), you can do it by making a custom binding adapter.

In other words, doing something like this:

public class FontBindingAdapter {

    @BindingAdapter({"bind:font"})
    public static void setFont(TextView textView, String typefaceName){
        Typeface typeface = ResourcesCompat.getFont(context, R.font.myfont);
        // You'd probably want to actually use `typefaceName` to determine the font to use 
        textView.setTypeface(typeface);
    }

Then in your layout, like this:

<TextView
   app:font="@{some_condition ? @string/typeface_string_name_bold: @string/typeface_string_name_bold_light}"

I used this in my code, based on a great post: https://plus.google.com/+LisaWrayZeitouni/posts/LTr5tX5M9mb

Matthew Horst
  • 1,991
  • 15
  • 18
  • 1
    Nice idea, unfortunately you cannot set styles programmatically (only when instantiating and adding the view yourself) – DarkLeafyGreen Apr 07 '17 at 15:02
  • If dealing with fonts, Android O now has much better support for them: "Android O introduces a new feature, Fonts in XML, which lets you use fonts as resources" (https://developer.android.com/preview/features/working-with-fonts.html) – Matthew Horst Apr 07 '17 at 15:43
3

I have a found a rather elegant solution for applying styles with data binding. I use the Paris library and then create binding adapters for interested views. for example:

@BindingAdapter("bindTextViewStyle")
fun TextView.bindTextViewStyle(styleResourceId: Int) {
    this.style(styleResourceId)
}

and then in XML:

<TextView
    app:bindTextViewStyle="@{viewModel.priceStyleResource}"
    .../>

viewModel.priceStyleResource is a MutableLiveData in my view model which is set with the style resource ID.

priceStyleResource.value = R.style.QuoteDetailsHeaderItem_Up

EXTRA NOTE

You can also probably make a generic bindStyle binding adapter directly for the View class, but in that case the attribute items specifically for textviews (textColor for example) will not get applied. So up to you to find the right balance and naming.

Raphael C
  • 2,296
  • 1
  • 22
  • 22
2

Nowadays, we can set the textAppearance (subset of style) in this way:

android:textAppearance='@{viewModel.messageCount > 0 ? R.style.B5_error : R.style.B5_error}'

Don't forget to import "R" from YOUR project.

Correct

<import type="com.company.project.R" />

   

Incorrect:

<import type="android.R"/>
Ponomarenko Oleh
  • 732
  • 2
  • 12
  • 25
  • 1
    This works, but `android:textAppearance` is just a subset and not a complete replacement of `style` attribute. – Salvador Apr 01 '23 at 20:35