Ottieni il valore del colore a livello di codice quando è un riferimento (tema)


116

Considera questo:

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>

Quindi il colore del tema fa riferimento al tema. Come posso ottenere il theme_color (riferimento) a livello di programmazione? Normalmente lo userei getResources().getColor()ma non in questo caso perché referenziato!

Risposte:


255

Questo dovrebbe fare il lavoro:

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

Assicurati inoltre di applicare il tema alla tua attività prima di chiamare questo codice. O usa:

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

nel tuo manifest o call (prima di chiamare setContentView(int)):

setTheme(R.style.Theme_BlueTheme)

in onCreate().

L'ho testato con i tuoi valori e ha funzionato perfettamente.


grazie non posso ancora provare la tua soluzione perché ricevo un errore: stackoverflow.com/questions/17278244/… Forse hai esperienza in questo ...
Seraphim's

5
Ad ogni modo, con la tua soluzione ottengo un valore di colore 0 (TypedValue {t = 0x0 / d = 0x0}) ... Non uso declare-styleable, solo un riferimento al colore
Seraphim's

Applichi il tema alla tua attività?
Emanuel Moecklin

5
Se non desideri applicare il tema all'attività, puoi creare un ContextThemeWrappertema utilizzando l'id del tema e quindi recuperare il tema da quello.
Ted Hopp

1
Questo metodo funziona su Android X (material designing)
BlackBlind

43

Da aggiungere alla risposta accettata, se stai usando kotlin.

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

e poi nella tua attività puoi fare

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


2
ok, grazie per l '"integrazione". Non sto usando kotlin ma è interessante.
Seraphim's

5
Bene, rende TypedValue visibile al mondo esterno. E per i colori vuoi sempre risolvere le dichiarazioni referenziali, quindi ho questo: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = TypedValue().let { theme.resolveAttribute(attribute, it, true); it.data }(formattato male qui ma va bene)
milosmns

1
L'utilizzo sarebbe come questo:val errorColor = context.getThemeColor(R.attr.colorError)
milosmns

Modo più universale, che recupera anche il valore predefinito per a ColorStateList: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = obtainStyledAttributes(intArrayOf(attribute)).use { it.getColor(0, Color.MAGENTA) }(da Nick Butcher )
gmk57

Modo definitivo, che recupera il tutto ColorStateList, anche se fa riferimento ad altri attributi del tema: fun Context.getThemeColor(@AttrRes attribute: Int): ColorStateList = TypedValue().let { theme.resolveAttribute(attribute, it, true); AppCompatResources.getColorStateList(this, it.resourceId) }(anche i singoli colori saranno inseriti in una ColorStateList).
gmk57

24

Questo ha funzionato per me:

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

se vuoi estrarre la stringa esadecimale:

Integer.toHexString(color)

Questo dovrebbe restituire un ColorRes, non un ColorInt.
Miha_x64

Ho finito per usarlo con getColorResource (color) e non chiamare recycle.
Zeek Aran

2

Se vuoi ottenere più colori puoi usare:

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

Aggiungi questo al tuo build.gradle (app):

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

E aggiungi questa funzione di estensione da qualche parte nel tuo codice:

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

0

Ecco un metodo di utilità Java conciso che accetta più attributi e restituisce un array di interi di colore. :)

/**
 * @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 è meglio di Kotlin per questo?
IgorGanapolsky il

@IgorGanapolsky Oh, onestamente non lo so. Ho condiviso il mio codice poiché sapevo che sarebbe tornato utile a qualcuno là fuori! Non conosco Kotlin e presumo che Kotlin non lo farebbe funzionare meglio, forse meno righe di codice! : P
varun

-1

Per coloro che sono alla ricerca di riferimenti a un disegno da utilizzare falsein formatoresolveRefs

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


Qual è la variabile typedValue in riferimento a?
BENN1 °

Qual è il tema variabile. * In riferimento a?
BENN1 °
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.