How to retrieve style attributes programmatically from styles.xml
It is possible to retrieve custom styles from styles.xml
programmatically.
Define some arbitrary style in styles.xml
:
<style name="MyCustomStyle">
<item name="android:textColor">#efefef</item>
<item name="android:background">#ffffff</item>
<item name="android:text">This is my text</item>
</style>
Now, retrieve the styles like this
// The attributes you want retrieved
int[] attrs = {android.R.attr.textColor, android.R.attr.background, android.R.attr.text};
// Parse MyCustomStyle, using Context.obtainStyledAttributes()
TypedArray ta = obtainStyledAttributes(R.style.MyCustomStyle, attrs);
// Fetch the text from your style like this.
String text = ta.getString(2);
// Fetching the colors defined in your style
int textColor = ta.getColor(0, Color.BLACK);
int backgroundColor = ta.getColor(1, Color.BLACK);
// Do some logging to see if we have retrieved correct values
Log.i("Retrieved text:", text);
Log.i("Retrieved textColor as hex:", Integer.toHexString(textColor));
Log.i("Retrieved background as hex:", Integer.toHexString(backgroundColor));
// OH, and don't forget to recycle the TypedArray
ta.recycle()
The answer @Ole has given seems to break when using certain attributes, such as shadowColor, shadowDx, shadowDy, shadowRadius (these are only a few I found, there might be more)
I have no idea as to why this issue occurs, which I am asking about here, but @AntoineMarques coding style seems to solve the issue.
To make this work with any attribute it would be something like this
First, define a stylable to contain the resource ids like so
attrs.xml
<resources>
<declare-styleable name="MyStyle" >
<attr name="android:textColor" />
<attr name="android:background" />
<attr name="android:text" />
</declare-styleable>
</resources>
Then in code you would do this to get the text.
TypedArray ta = obtainStyledAttributes(R.style.MyCustomStyle, R.styleable.MyStyle);
String text = ta.getString(R.styleable.MyStyle_android_text);
The advantage of using this method is, you are retrieving the value by name and not an index.
The answers from Ole and PrivatMamtora didn't work well for me, but this did.
Let's say I wanted to read this style programmatically:
<style name="Footnote">
<item name="android:fontFamily">@font/some_font</item>
<item name="android:textSize">14sp</item>
<item name="android:textColor">@color/black</item>
</style>
I could do it like this:
fun getTextColorSizeAndFontFromStyle(
context: Context,
textAppearanceResource: Int // Can be any style in styles.xml like R.style.Footnote
) {
val typedArray = context.obtainStyledAttributes(
textAppearanceResource,
R.styleable.TextAppearance // These are added to your project automatically.
)
val textColor = typedArray.getColorStateList(
R.styleable.TextAppearance_android_textColor
)
val textSize = typedArray.getDimensionPixelSize(
R.styleable.TextAppearance_android_textSize
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val typeface = typedArray.getFont(R.styleable.TextAppearance_android_fontFamily)
// Do something with the typeface...
} else {
val fontFamily = typedArray.getString(R.styleable.TextAppearance_fontFamily)
?: when (typedArray.getInt(R.styleable.TextAppearance_android_typeface, 0)) {
1 -> "sans"
2 -> "serif"
3 -> "monospace"
else -> null
}
// Do something with the fontFamily...
}
typedArray.recycle()
}
I took some inspiration from Android's TextAppearanceSpan class, you can find it here: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/text/style/TextAppearanceSpan.java
I was not able to get the earlier solutions to work.
My style is:
<style name="Widget.TextView.NumPadKey.Klondike" parent="Widget.TextView.NumPadKey">
<item name="android:textSize">12sp</item>
<item name="android:fontFamily">sans-serif</item>
<item name="android:textColor">?attr/wallpaperTextColorSecondary</item>
<item name="android:paddingBottom">0dp</item>
</style>
The obtainStyledAttributes() for android.R.attr.textSize gives String results of "12sp" which I then have to parse. For android.R.attr.textColor it gave a resource file XML name. This was much too cumbersome.
Instead, I found an easy way using ContextThemeWrapper.
TextView sample = new TextView(new ContextThemeWrapper(getContext(), R.style.Widget_TextView_NumPadKey_Klondike), null, 0);
This gave me a fully-styled TextView to query for anything I want. For example:
float textSize = sample.getTextSize();