How to reference style attributes from a drawable?
Solution 1
In my experience it is not possible to reference an attribute in an XML drawable.
In order to make your theme you need to:
- Create one XML drawable per theme.
-
Include the needed color into you drawable directly with the
@color
tag or #RGB format.
Make an attribute for your drawable in attrs.xml.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Attributes must be lowercase as we want to use them for drawables -->
<attr name="my_drawable" format="reference" />
</resources>
Add your drawable to your theme.xml.
<style name="MyTheme" parent="@android:style/Theme.NoTitleBar">
<item name="my_drawable">@drawable/my_drawable</item>
</style>
Reference your drawable in your layout using your attribute.
<TextView android:background="?my_drawable" />
Solution 2
Starting with lollipop
(API 21) this feature is supported, see
https://code.google.com/p/android/issues/detail?id=26251
However, if you're targeting devices without lollipop, don't use it, as it will crash, use the workaround in the accepted answer instead.
Solution 3
Although it's not possible to reference style attributes from drawables on pre-Lollipop devices, but it's possible for color state lists. You can use AppCompatResources.getColorStateList(Context context, int resId) method from Android Support Library. The downside is that you will have to set those color state lists programmatically.
Here is a very basic example.
color/my_color_state.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="?colorControlActivated" />
<item android:color="?colorControlNormal" />
</selector>
A widget that needs a color state list:
<RadioButton
android:id="@+id/radio_button"
android:text="My Radio" />
And the most important:
ColorStateList csl = AppCompatResources.getColorStateList(context, R.color.my_color_state);
RadioButton r = (RadioButton) findViewById(R.id.radio_button);
r.setTextColor(csl);
Well, not the most elegant or shortest way, but this is what Android Support Library does to make it work on older versions (pre-Lollipop) of Android.
Unfortunately, the similar method for drawables doesn't work with style attributes.
Solution 4
I answered the same question in https://stackoverflow.com/a/59467269/3841352 but i will post it here as well:
I encountered the same problem and as of 2019 it hasn't been resolved so you can't have an attribute referenced in a selector as a drawable. I will share the solution I got for the problem as I don't see it posted in here. I found it in the last comment of the bug report.
The workaround is basically create a drawable resource that will be the one referring the attribute value.
To illustrate your case the solution would be instead of:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?attr/colorPrimary" android:state_enabled="true" android:state_window_focused="false"/>
<item android:drawable="?attr/colorPrimaryDark" android:state_pressed="true"/>
<item android:drawable="@android:color/darker_gray" android:state_enabled="false"/>
<item android:drawable="?attr/colorPrimary"/>
</selector>
you would replace the ?attr/* for a drawable resource:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/colorPrimaryDrawable" android:state_enabled="true" android:state_window_focused="false"/>
<item android:drawable="@drawable/colorPrimaryDarkDrawable" android:state_pressed="true"/>
<item android:drawable="@android:color/darker_gray" android:state_enabled="false"/>
<item android:drawable="@drawable/colorPrimaryDrawable"/>
</selector>
The drawables would be defined as:
drawable/colorPrimaryDrawable
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
<solid android:color="?attr/colorPrimary" />
</shape>
drawable/colorPrimaryDarkDrawable
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
<solid android:color="?attr/colorPrimaryDark" />
</shape>
Hope it helps!!
Related videos on Youtube
MM.
Updated on December 25, 2020Comments
-
MM. over 3 years
I want to have 2 selectable themes for my application. In order to do that, I defined some attributes, like this:
<attr format="color" name="item_background" />
Then, I created both themes, like this:
<style name="ThemeA"> <item name="item_background">#123456</item> </style> <style name="ThemeB"> <item name="item_background">#ABCDEF</item> </style>
This method works great, allowing me to create and modify several themes easily. The problem is that it seems that it can be used only in Views, and not in Drawables.
For example, referencing a value from a View inside a layout works:
<TextView android:background="?item_background" />
But doing the same in a Drawable doesn't:
<shape android:shape="rectangle"> <solid android:color="?item_background" /> </shape>
I get this error when running the application:
java.lang.UnsupportedOperationException: Can't convert to color: type=0x2
If instead of
?item_background
I use a hardcoded color, it works, but that doesn't allow me to use my themes. I also tried?attr:item_background
, but the same happens.How could I do this? And why does it work in Views but not in Drawables? I can't find this limitation anywhere in the documentation...
-
Bahadır Yıldırım over 12 yearsThis might be a duplicate of the following question: stackoverflow.com/questions/7529574/…
-
user123321 over 12 years@Martin M., what did you figure out with this?
-
Guillaume over 12 yearsAny solution for that yet? I'm hitting the exact same wall
-
HGPB almost 12 yearsAnother more recent question here: stackoverflow.com/q/12115125/317889 Same problem. Sort it out Google.
-
Bianca Daniciuc almost 10 yearsApparently this issue was solved in Android L preview, as specified here: code.google.com/p/android/issues/detail?id=26251
-
MM. almost 10 yearsWow! Better late than never I guess :)
-
Davideas about 9 yearsThanks to this question... It's nice to know that it is fixed but our code runs on different pre-L devices. So we have to maintain different drawables anyway. Can somebody confirm?
-
-
Davideas about 9 yearsIt seems that, this solution is still necessary if you want keep compatibility... Yes from L it is fixed and Theme color is well referenced, but same code runs on different pre-L devices and actually the attr reference doesn't work on pre-L devices! LoL.. So for me it is not fixed if I have to maintain different drawables anyway.
-
Tiksi almost 9 yearsI wish I could upvote this twice. Just tried to streamline my shapes to use references instead of hardcoded #RGB and got the same error. Came to SO for a solution and found this same answer that I upvoted 2 weeks ago! (facepalm)
-
Ivan over 8 yearsIs there any chance to use kind of support library to make it work on a pre L APIs ?
-
marmor over 8 yearsNo, the support library is a set of APIs that can be used on older devices, this behavior change is in the compiler and build tools, so it's not related to the support library.
-
Adrian Sicaru over 8 yearsNo, in lollipop it was not an implemented feature, but a glaring bug fix. And a serious bug at that.
-
Umair over 8 yearsThank you mate. You're a rockstar!!
-
MariusBudin over 8 yearsThis is super ninja!
-
Camilo Casadiego over 8 yearsbefore posting a new question I wanna ask here, I'm having the "type=0x2" on this <ProgressBar android:id="@+id/progressbar" android:progressDrawable="@drawable/progress_single_input_form" android:layout_width="match_parent" android:layout_gravity="bottom"/> What I'm missing? (that part of a biger xml, and when I remove it, everything else works), this only happens on andorid 4.2.2
-
L. G. over 8 yearsDifficult to answer with so few informations, I recommend you to post a question with a detailed description of the problem.
-
filthy_wizard over 8 yearsdamn, i thought i had a nice theming solution. now I have to go back and create a bunch of button selector drawables.
-
NeilS almost 8 yearsSounds hopeful! But the problem is in the Drawable shape not a View. I have an appcompat view referencing (as background) a shape which uses attr to get a themed colour and it falls over with the above error on <21. Is there an appcompat drawable I've missed?
-
Stephan Henningsen over 7 yearsARGH! This should be top priority for Google to make a backport-fix for! The ?attr-reference notation is so extremely useful and important that it's so close to impossible to live without if you have multiple themes within an app. Right now I have to make three drawable XMLs for each of custom button types!
-
Santiago SR over 7 yearsHi. It is possible reference custom attr from drawable but on API 21 and above. Paste an example.
-
Adnan Abdollah Zaki over 7 yearsThats i want . very simple and nice solution in < 21 SDK .
-
Shamsul Arefin about 6 yearsThat's easy, but, for a new theme, have to add new files for all the UI elements, that's long task
-
maXp about 6 yearsGoogle WTF??? Why why why?... is any simple task in android always very difficult?! WTF?!
-
HendraWD about 6 yearsBut there is another error when I implemented it
Caused by: android.content.res.Resources$NotFoundException: Resource is not a Drawable (color or path): TypedValue{t=0x2/d=0x7f040134 a=-1}
-
southerton over 4 yearsAndroid 5.0.1 jy Huawei still affected.