206

Consider this:

styles.xml

<style name="BlueTheme" parent="@android:style/Theme.Black.NoTitleBar"> <item name="theme_color">@color/theme_color_blue</item> </style> 

attrs.xml

<attr name="theme_color" format="reference" /> 

color.xml

<color name="theme_color_blue">#ff0071d3</color> 

So the theme color is referenced by the theme. How can I get the theme_color (reference) programmatically? Normally I would use getResources().getColor() but not in this case because it's referenced!

12 Answers 12

355

This should do the job:

TypedValue typedValue = new TypedValue(); Theme theme = context.getTheme(); theme.resolveAttribute(R.attr.theme_color, typedValue, true); @ColorInt int color = typedValue.data; 

Also make sure to apply the theme to your Activity before calling this code. Either use:

android:theme="@style/Theme.BlueTheme" 

in your manifest or call (before you call setContentView(int)):

setTheme(R.style.Theme_BlueTheme) 

in onCreate().

I've tested it with your values and it worked perfectly.

Sign up to request clarification or add additional context in comments.

12 Comments

Anyway, with your solution I get a 0 value color (TypedValue{t=0x0/d=0x0})... I do not use declare-styleable, just a reference to the color
If you don't want to apply the theme to the activity, you can create a ContextThemeWrapper using the theme id and then retrieve the theme from that.
This method works in android X (material designing)
This method doesn't work if theme_color references a ColorStateList: you can use this solution to get default color or AppCompatResources.getColorStateList(context, typedValue.resourceId) to get ColorStateList object.
Now built in. The following is equivalent: MaterialColors.getColor(context, R.attr.colorError, Color.GRAY)
|
119

We can use the utility class provided by Material Design library:

int color = MaterialColors.getColor(context, R.attr.theme_color, Color.BLACK) 

NOTE: Color.BLACK is the default color in case the attribute supplied to the u

5 Comments

The best answer out of all
For sure using the MaterialColors utility class is the recommended way. Even is possible to get theme color base on a view: val primaryColor = MaterialColors.getColor(view, R.attr.colorPrimary)
This should be an accepted answer now in 2021
In my case "android.R.attr.textColorSecondary" for example is not working. Its just transparent. But the default color is not used, so i am stuck with this problem. Any help?
@tzanke check your styles, mby you didnt declare android:textColorSecondary, not textColorSecondary. also make sure that the context had applied that style
92

To add to the accepted answer, if you're using kotlin.

@ColorInt fun Context.getColorFromAttr( @AttrRes attrColor: Int, typedValue: TypedValue = TypedValue(), resolveRefs: Boolean = true ): Int { theme.resolveAttribute(attrColor, typedValue, resolveRefs) return typedValue.data } 

and then in your activity you can do

textView.setTextColor(getColorFromAttr(R.attr.color))

6 Comments

oook, thanks for the "integration". I'm not using kotlin but it's interesting.
Well it makes TypedValue visible to the outside world. And for colors you always want to resolve referential declarations, so I have this: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = TypedValue().let { theme.resolveAttribute(attribute, it, true); it.data } (poorly formatted here but it's ok)
Usage would be like this: val errorColor = context.getThemeColor(R.attr.colorError)
More universal way, which also retrieves default value for a ColorStateList: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = obtainStyledAttributes(intArrayOf(attribute)).use { it.getColor(0, Color.MAGENTA) } (from Nick Butcher)
Ultimate way, which retrieves the whole ColorStateList, even if it references another theme attributes: fun Context.getThemeColor(@AttrRes attribute: Int): ColorStateList = TypedValue().let { theme.resolveAttribute(attribute, it, true); AppCompatResources.getColorStateList(this, it.resourceId) } (single colors will be wrapped in a ColorStateList too).
|
32

2021/January/8

If you want to get color from theme attributes, use the following steps.

Create a variable my_color and store the color from theme attributes as,

val my_color = MaterialColors.getColor(<VIEWOBJECT>, R.attr.<YOUATRRIBUTENAME>) 

In place of <VIEWOBJECT>, pass a view object where you want to use the color, (behind the scenes it's just used to get the context as <VIEWOBJECT>.getContext() so that it can access resource i.e theme attribute values) . In place of <YOURATTRIBUTENAME>, use the name of the atrribute that you want to access

Example 1:

If you want want to get color referenced by theme attributes from certain activity. Create a variable that represents a view object on which you want to use the color. Here i have a textView in my activity, i'll just reference its object inside textview variable and pass it to the getColor method and behind the scenes it'll use that object to just get the context, so that it can access theme attribute values

val textview: TextView = findViewById(R.id.mytextview) val my_color = MaterialColors.getColor(textView, R.attr<YOURATTRIBUTENAME>) 

Example 2 :

If you want to get color from theme attributes inside a custom view then just use,

val my_color = MaterialColors.getColor(this, R.attr.<YOUATRRIBUTENAME>) 

Inside a custom view this refers to the object of the custom view, which is in fact a view object.

Comments

25

This worked for me:

int[] attrs = {R.attr.my_attribute}; TypedArray ta = context.obtainStyledAttributes(attrs); int color = ta.getResourceId(0, android.R.color.black); ta.recycle(); 

if you want to get the hexstring out of it:

Integer.toHexString(color) 

2 Comments

This should return a ColorRes, not a ColorInt.
I ended up using this with getColorResource(color) and not calling recycle.
14

Add this to your build.gradle (app):

implementation 'androidx.core:core-ktx:1.1.0' 

And add this extension function somewhere in your code:

import androidx.core.content.res.use @ColorInt @SuppressLint("Recycle") fun Context.themeColor( @AttrRes themeAttrId: Int ): Int { return obtainStyledAttributes( intArrayOf(themeAttrId) ).use { it.getColor(0, Color.MAGENTA) } } 

1 Comment

I wanted to get color from android.R.attr.textColorSecondary reference and only this solution worked. thanks.
4

I use this kotlin extension

@ColorInt fun Context.getColorFromAttr( @AttrRes attrColor: Int ): Int { val typedArray = theme.obtainStyledAttributes(intArrayOf(attrColor)) val textColor = typedArray.getColor(0, 0) typedArray.recycle() return textColor } 

sample

getColorFromAttr(android.R.attr.textColorSecondary) 

Comments

2

If you want to get multiple colors you can use:

int[] attrs = {R.attr.customAttr, android.R.attr.textColorSecondary, android.R.attr.textColorPrimaryInverse}; Resources.Theme theme = context.getTheme(); TypedArray ta = theme.obtainStyledAttributes(attrs); int[] colors = new int[attrs.length]; for (int i = 0; i < attrs.length; i++) { colors[i] = ta.getColor(i, 0); } ta.recycle(); 

Comments

1

For those who are looking for reference to a drawable you should use false in resolveRefs

theme.resolveAttribute(R.attr.some_drawable, typedValue, **false**);

2 Comments

Whats the variable typedValue in reference to?
Whats the variable theme.* in reference to?
1

With me it only worked using ContextCompat and the typedValue.resourceId

As proposed in this question: How to get a value of color attribute programmatically

TypedValue typedValue = new TypedValue(); getTheme().resolveAttribute(R.attr.colorControlNormal, typedValue, true); int color = ContextCompat.getColor(this, typedValue.resourceId) 

1 Comment

idk why returns -1
0

Here's a concise Java utility method that takes multiple attributes and return an array of color integers. :)

/** * @param context Pass the activity context, not the application context * @param attrFields The attribute references to be resolved * @return int array of color values */ @ColorInt static int[] getColorsFromAttrs(Context context, @AttrRes int... attrFields) { int length = attrFields.length; Resources.Theme theme = context.getTheme(); TypedValue typedValue = new TypedValue(); @ColorInt int[] colorValues = new int[length]; for (int i = 0; i < length; ++i) { @AttrRes int attr = attrFields[i]; theme.resolveAttribute(attr, typedValue, true); colorValues[i] = typedValue.data; } return colorValues; } 

2 Comments

Java is better than Kotlin for this?
@IgorGanapolsky Oh, I honestly do not know. I shared my code since I knew it would come in handy to someone out there! I do not know Kotlin and I presume that Kotlin wouldn't make it perform any better, maybe fewer lines of code! :P
0

For me now this is the best way to control colors when theme is dark and light

val color = if (isSystemInDarkTheme()) Color.Black else Color.White isSystemInDark() //this code return a true or a false 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.