Obtenir la valeur de la couleur par programme lorsqu'il s'agit d'une référence (thème)


116

Considère ceci:

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>

La couleur du thème est donc référencée par le thème. Comment puis-je obtenir le theme_color (référence) par programmation? Normalement j'utiliserais getResources().getColor()mais pas dans ce cas car c'est référencé!

Réponses:


255

Cela devrait faire le travail:

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

Assurez-vous également d'appliquer le thème à votre activité avant d'appeler ce code. Soit utiliser:

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

dans votre manifeste ou appel (avant d'appeler setContentView(int)):

setTheme(R.style.Theme_BlueTheme)

dans onCreate().

Je l'ai testé avec vos valeurs et cela a parfaitement fonctionné.


merci je ne peux pas encore essayer votre solution car j'obtiens une erreur: stackoverflow.com/questions/17278244/... Peut-être que vous avez de l'expérience dans ce domaine ...
Seraphim's

5
Quoi qu'il en soit, avec votre solution, j'obtiens une couleur de valeur 0 (TypedValue {t = 0x0 / d = 0x0}) ... Je n'utilise pas declare-styleable, juste une référence à la couleur
Seraphim's

Appliquez-vous le thème à votre activité?
Emanuel Moecklin

5
Si vous ne souhaitez pas appliquer le thème à l'activité, vous pouvez créer un ContextThemeWrapperà l'aide de l'ID de thème, puis récupérer le thème à partir de celui-ci.
Ted Hopp

1
Cette méthode fonctionne dans Android X (conception de matériaux)
BlackBlind

43

Pour ajouter à la réponse acceptée, si vous utilisez kotlin.

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

et puis dans ton activité tu peux faire

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


2
oook, merci pour "l'intégration". Je n'utilise pas kotlin mais c'est intéressant.
Seraphim's le

5
Eh bien, cela rend TypedValue visible au monde extérieur. Et pour les couleurs, vous voulez toujours résoudre les déclarations référentielles, donc j'ai ceci: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = TypedValue().let { theme.resolveAttribute(attribute, it, true); it.data }(mal formaté ici mais c'est ok)
milosmns

1
L'utilisation serait comme ceci:val errorColor = context.getThemeColor(R.attr.colorError)
milosmns

De manière plus universelle, qui récupère également la valeur par défaut pour a ColorStateList: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = obtainStyledAttributes(intArrayOf(attribute)).use { it.getColor(0, Color.MAGENTA) }(de Nick Butcher )
gmk57

Méthode ultime, qui récupère le tout ColorStateList, même s'il fait référence à un autre attribut de thème: fun Context.getThemeColor(@AttrRes attribute: Int): ColorStateList = TypedValue().let { theme.resolveAttribute(attribute, it, true); AppCompatResources.getColorStateList(this, it.resourceId) }(les couleurs uniques seront également enveloppées dans un ColorStateList).
gmk57 du

24

Cela a fonctionné pour moi:

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

si vous voulez en extraire la chaîne hexadécimale:

Integer.toHexString(color)

Cela devrait renvoyer un ColorRes, pas un ColorInt.
Miha_x64

J'ai fini par l'utiliser avec getColorResource (couleur) et sans appeler recycle.
Zeek Aran

2

Si vous souhaitez obtenir plusieurs couleurs, vous pouvez utiliser:

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();

2

Ajoutez ceci à votre build.gradle (application):

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

Et ajoutez cette fonction d'extension quelque part dans votre code:

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

0

Voici une méthode d'utilitaire Java concise qui prend plusieurs attributs et renvoie un tableau d'entiers de couleur. :)

/**
 * @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;
}

Java est meilleur que Kotlin pour cela?
IgorGanapolsky

@IgorGanapolsky Oh, honnêtement, je ne sais pas. J'ai partagé mon code car je savais qu'il serait utile à quelqu'un là-bas! Je ne connais pas Kotlin et je suppose que Kotlin ne le ferait pas mieux fonctionner, peut-être moins de lignes de code! : P
varun

-1

Pour ceux qui recherchent une référence à un dessinable, vous devriez utiliser falsedansresolveRefs

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


Quelle est la variable typedValue en référence?
BENN1TH

Quel est le thème variable. * En référence?
BENN1TH
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.