Farbwert programmgesteuert abrufen, wenn es sich um eine Referenz (Thema) handelt


114

Bedenken Sie:

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>

Die Themenfarbe wird also vom Thema referenziert. Wie kann ich die theme_color (Referenz) programmgesteuert abrufen? Normalerweise würde ich verwenden, getResources().getColor()aber nicht in diesem Fall, weil es referenziert!

Antworten:


252

Dies sollte den Job machen:

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

Stellen Sie außerdem sicher, dass Sie das Thema auf Ihre Aktivität anwenden, bevor Sie diesen Code aufrufen. Verwenden Sie entweder:

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

in Ihrem Manifest oder Anruf (bevor Sie anrufen setContentView(int)):

setTheme(R.style.Theme_BlueTheme)

in onCreate().

Ich habe es mit Ihren Werten getestet und es hat perfekt funktioniert.


danke Ich kann Ihre Lösung noch nicht ausprobieren, da ich eine Fehlermeldung erhalte : stackoverflow.com/questions/17278244/… Vielleicht haben Sie Erfahrung damit ...
Seraphims

5
Wie auch immer, mit Ihrer Lösung erhalte ich eine Farbe mit 0 Werten (TypedValue {t = 0x0 / d = 0x0}) ... Ich verwende keine deklarierbare Farbe, nur einen Verweis auf die Farbe
Seraphims

Wenden Sie das Thema auf Ihre Aktivität an?
Emanuel Moecklin

5
Wenn Sie das Thema nicht auf die Aktivität anwenden möchten, können Sie eine ContextThemeWrappermit der Themen-ID erstellen und dann das Thema daraus abrufen.
Ted Hopp

1
Diese Methode funktioniert in Android X (Materialdesign)
BlackBlind

41

Hinzufügen zur akzeptierten Antwort, wenn Sie Kotlin verwenden.

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

und dann können Sie in Ihrer Aktivität tun

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


2
oook, danke für die "Integration". Ich benutze kein Kotlin, aber es ist interessant.
Seraphim

5
Nun, es macht TypedValue für die Außenwelt sichtbar. Und für Farben möchten Sie immer referenzielle Deklarationen auflösen, also habe ich @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = TypedValue().let { theme.resolveAttribute(attribute, it, true); it.data }
Folgendes

1
Die Verwendung wäre wie val errorColor = context.getThemeColor(R.attr.colorError)
folgt

Universeller Weg, der auch den Standardwert für a abruft ColorStateList: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = obtainStyledAttributes(intArrayOf(attribute)).use { it.getColor(0, Color.MAGENTA) }(von Nick Butcher )
gmk57

Ultimative Methode, mit der das Ganze abgerufen wird ColorStateList, auch wenn auf andere Themenattribute verwiesen wird: fun Context.getThemeColor(@AttrRes attribute: Int): ColorStateList = TypedValue().let { theme.resolveAttribute(attribute, it, true); AppCompatResources.getColorStateList(this, it.resourceId) }(Einzelne Farben werden ebenfalls in eine eingeschlossen ColorStateList).
gmk57

24

Das hat bei mir funktioniert:

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

Wenn Sie den Hexstring herausholen möchten:

Integer.toHexString(color)

Dies sollte ein ColorRes zurückgeben, kein ColorInt.
Miha_x64

Am Ende habe ich dies mit getColorResource (Farbe) verwendet und nicht recycle aufgerufen.
Zeek Aran

2

Wenn Sie mehrere Farben erhalten möchten, können Sie Folgendes verwenden:

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

Fügen Sie dies Ihrem build.gradle (App) hinzu:

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

Und fügen Sie diese Erweiterungsfunktion irgendwo in Ihren Code ein:

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

0

Hier ist eine übersichtliche Java-Dienstprogrammmethode, die mehrere Attribute verwendet und ein Array von Farb-Ganzzahlen zurückgibt. :) :)

/**
 * @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 ist dafür besser als Kotlin?
IgorGanapolsky

@IgorGanapolsky Oh, ich weiß es ehrlich gesagt nicht. Ich habe meinen Code geteilt, da ich wusste, dass er für jemanden da draußen nützlich sein würde! Ich kenne Kotlin nicht und ich gehe davon aus, dass Kotlin es nicht besser machen würde, vielleicht weniger Codezeilen! : P
varun

-1

Für diejenigen, die Bezugnahme auf eine ziehbar suchen Sie verwenden sollten falseinresolveRefs

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


Worauf bezieht sich die Variable typedValue?
BENN1TH

Was ist das variable Thema. * In Bezug auf?
BENN1TH
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.