Uzyskaj programowo wartość koloru, gdy jest to odniesienie (motyw)

116

Rozważ to:

style.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>

Więc kolor motywu jest powiązany z motywem. Jak programowo uzyskać atrybut theme_color (reference)? Normalnie użyłbym, getResources().getColor()ale nie w tym przypadku, ponieważ jest on przywoływany!

Serafinów
źródło

Odpowiedzi:

255

To powinno wystarczyć:

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

Upewnij się również, że zastosowałeś motyw do swojego działania przed wywołaniem tego kodu. Albo użyj:

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

w swoim manifeście lub wezwaniu (zanim zadzwonisz setContentView(int)):

setTheme(R.style.Theme_BlueTheme)

w onCreate().

Przetestowałem to z twoimi wartościami i działało doskonale.

Emanuel Moecklin
źródło
dzięki Nie mogę jeszcze wypróbować twojego rozwiązania, ponieważ pojawia się błąd: stackoverflow.com/questions/17278244/… Może masz w tym doświadczenie ...
Seraphim's
5
W każdym razie z twoim rozwiązaniem otrzymuję kolor o wartości 0 (TypedValue {t = 0x0 / d = 0x0}) ... Nie używam deklarowanego stylu, tylko odniesienie do koloru
Seraphim's
Czy stosujesz motyw do swojej działalności?
Emanuel Moecklin
5
Jeśli nie chcesz zastosować motywu do działania, możesz utworzyć szablon ContextThemeWrapperprzy użyciu identyfikatora motywu, a następnie pobrać z niego motyw.
Ted Hopp
1
Ta metoda działa w
systemie
43

Aby dodać do zaakceptowanej odpowiedzi, jeśli używasz kotlin.

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

a potem w swojej działalności możesz to zrobić

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

Bri6ko
źródło
2
oook, dzięki za "integrację". Nie używam Kotlina, ale to interesujące.
Seraphim's
5
Cóż, sprawia, że ​​TypedValue jest widoczny dla świata zewnętrznego. A dla kolorów zawsze chcesz rozwiązać deklaracje referencyjne, więc mam to: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = TypedValue().let { theme.resolveAttribute(attribute, it, true); it.data }(źle sformatowane tutaj, ale jest ok)
milosmns
1
Sposób użycia byłby taki:val errorColor = context.getThemeColor(R.attr.colorError)
milosmns
Bardziej uniwersalny sposób, który również pobiera domyślną wartość dla ColorStateList: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = obtainStyledAttributes(intArrayOf(attribute)).use { it.getColor(0, Color.MAGENTA) }(od Nicka Butchera )
gmk57
Ostateczny sposób, który pobiera całość ColorStateList, nawet jeśli odwołuje się do innych atrybutów motywu: fun Context.getThemeColor(@AttrRes attribute: Int): ColorStateList = TypedValue().let { theme.resolveAttribute(attribute, it, true); AppCompatResources.getColorStateList(this, it.resourceId) }(pojedyncze kolory też będą opakowane ColorStateList).
gmk57
24

To zadziałało dla mnie:

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

jeśli chcesz wyciągnąć z niego szesnastkowy ciąg:

Integer.toHexString(color)
Angel Solis
źródło
Powinno to zwrócić ColorRes, a nie ColorInt.
Miha_x64
Skończyło się na tym, że użyłem tego z getColorResource (kolor) i nie wywołałem recycle.
Zeek Aran
2

Jeśli chcesz uzyskać wiele kolorów, możesz użyć:

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
źródło
2

Dodaj to do swojego build.gradle (aplikacji):

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

I dodaj tę funkcję rozszerzenia gdzieś w swoim kodzie:

@ColorInt
@SuppressLint("Recycle")
fun Context.themeColor(
    @AttrRes themeAttrId: Int
): Int {
    return obtainStyledAttributes(
        intArrayOf(themeAttrId)
    ).use {
        it.getColor(0, Color.MAGENTA)
    }
}
André Ramon
źródło
0

Oto zwięzła metoda narzędzia Java, która pobiera wiele atrybutów i zwraca tablicę liczb całkowitych w kolorze. :)

/**
 * @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
źródło
Java jest do tego lepsza niż Kotlin?
IgorGanapolsky
@IgorGanapolsky Och, szczerze nie wiem. Udostępniłem swój kod, ponieważ wiedziałem, że przyda się komuś! Nie znam Kotlina i przypuszczam, że Kotlin nie sprawiłby, że działałby lepiej, może mniej linii kodu! : P
varun
-1

Dla tych, którzy szukają odniesienia do rysunków, powinieneś użyć falsewresolveRefs

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

Kilogram
źródło
Do czego odwołuje się zmienna typedValue?
BENN1TH
Do czego odnosi się zmienna theme. *?
BENN1TH