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!

Seraphims
quelle

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.

Emanuel Moecklin
quelle
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))

Bri6ko
quelle
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)
Engel Solis
quelle
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();
Nicolas
quelle
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)
    }
}
André Ramon
quelle
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;
}
varun
quelle
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**);

Kilo
quelle
Worauf bezieht sich die Variable typedValue?
BENN1TH
Was ist das variable Thema. * In Bezug auf?
BENN1TH