Отримати значення кольору програмно, коли це посилання (тема)


116

Врахуйте це:

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>

Тож колір теми посилається на тему. Як я можу отримати програму theme_color (посилання) програмно? Зазвичай я б використовував, getResources().getColor()але не в цьому випадку, тому що на нього посилається!

Відповіді:


254

Це має зробити цю роботу:

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

Також не забудьте застосувати тему до своєї діяльності перед тим, як викликати цей код. Будь-яке використання:

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

у своєму маніфесті чи дзвінку (перед тим, як дзвонити setContentView(int)):

setTheme(R.style.Theme_BlueTheme)

в onCreate().

Я перевірив це на ваших цінностях, і він працював чудово.


дякую, я не можу спробувати ваше рішення, тому що я отримую помилку: stackoverflow.com/questions/17278244/… Можливо, у вас є досвід у цьому ...
Серафім

5
У будь-якому випадку, за допомогою вашого рішення я отримую колір значення 0 (TypedValue {t = 0x0 / d = 0x0}) ... Я не використовую оголошення, яке може бути стилізоване, лише посилання на колір
Серафім

Чи застосовуєте ви тему до своєї діяльності?
Емануель Моеклін

5
Якщо ви не хочете застосовувати тему до дії, ви можете створити ContextThemeWrapperідентифікатор теми, а потім отримати тему з цього.
Тед Хопп

1
Цей метод працює в android X (проектування матеріалів)
BlackBlind

43

Щоб додати до прийнятої відповіді, якщо ви використовуєте kotlin.

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

а потім у своїй діяльності ви можете робити

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


2
oook, дякую за "інтеграцію". Я не використовую kotlin, але це цікаво.
Серафима

5
Ну, це робить TypedValue видимим для зовнішнього світу. А для кольорів ви завжди хочете вирішувати референтні декларації, тому я маю таке: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = TypedValue().let { theme.resolveAttribute(attribute, it, true); it.data }(тут погано відформатовано, але це нормально)
milosmns

1
Використання було б таким:val errorColor = context.getThemeColor(R.attr.colorError)
milosmns

Більш універсальний спосіб, який також отримує значення за замовчуванням для ColorStateList: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = obtainStyledAttributes(intArrayOf(attribute)).use { it.getColor(0, Color.MAGENTA) }(від Nick Butcher )
gmk57,

Кінцевий спосіб, який вилучає ціле ColorStateList, навіть якщо він посилається на інші атрибути теми: fun Context.getThemeColor(@AttrRes attribute: Int): ColorStateList = TypedValue().let { theme.resolveAttribute(attribute, it, true); AppCompatResources.getColorStateList(this, it.resourceId) }(окремі кольори теж будуть загорнуті ColorStateList).
gmk57

24

Це працювало для мене:

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

якщо ви хочете витягти з нього шістнадцятку:

Integer.toHexString(color)

Це має повернути ColorRes, а не ColorInt.
Miha_x64

Я в кінцевому рахунку використовував це за допомогою getColorResource (колір) і не викликав переробку.
Zeek Aran

2

Якщо ви хочете отримати кілька кольорів, ви можете використовувати:

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

Додайте це до свого build.gradle (програми):

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

І додайте цю функцію розширення десь у своєму коді:

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

0

Ось стислий метод утиліти Java, який бере декілька атрибутів та повертає масив цілих кольорів. :)

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

Ява краща за це Котлін?
ІгорГанапольський

@IgorGanapolsky О, я, чесно кажучи, не знаю. Я поділився своїм кодом, оскільки знав, що стане в нагоді комусь там! Я не знаю Котліна, і я припускаю, що Котлін не зробив би його кращим, можливо, менше рядків коду! : P
varun

-1

Для тих, хто шукає посилання на малюнок, який ви повинні використовувати falseвresolveRefs

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


Що стосується змінної typedValue стосовно?
BENN1TH

Що таке змінна тема. * Стосовно посилання?
BENN1TH
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.