Получить значение цвета программно, если это ссылка (тема)

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 (reference)? Обычно я бы использовал, getResources().getColor()но не в этом случае, потому что на него есть ссылка!

Серафима
источник

Ответы:

258

Это должно сработать:

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

Также не забудьте применить тему к своему Activity перед вызовом этого кода. Либо используйте:

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

в вашем манифесте или вызове (перед вызовом setContentView(int)):

setTheme(R.style.Theme_BlueTheme)

в onCreate().

Я проверил его с вашими ценностями, и он отлично сработал.

Эмануэль Моеклин
источник
спасибо, я пока не могу попробовать ваше решение, потому что получаю сообщение об ошибке: stackoverflow.com/questions/17278244/ ... Возможно, у вас есть опыт в этом ...
Серафим
5
В любом случае, с вашим решением я получаю цвет со значением 0 (TypedValue {t = 0x0 / d = 0x0}) ... Я не использую declare-styleable, просто ссылку на цвет
Seraphim's
Применяете ли вы тему к своей деятельности?
Emanuel Moecklin
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))

Bri6ko
источник
2
oook, спасибо за "интеграцию". Котлин не использую, но это интересно.
Seraphim's
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) }(от Ника Батчера )
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 (color), а не называл recycle.
Зик Аран
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;
}
Варуна
источник
Java лучше для этого Kotlin?
Игорь Ганапольский
@IgorGanapolsky Ой, если честно, не знаю. Я поделился своим кодом, так как знал, что он пригодится кому-то там! Я не знаю Kotlin и полагаю, что Kotlin не улучшит его работу, может быть, меньше строк кода! : P
varun
-1

Для тех, кто ищет ссылку на чертеж, вы должны использовать falseвresolveRefs

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

кило
источник
На что ссылается переменная typedValue?
BENN1TH
К чему относится переменная theme. *?
BENN1TH