Dapatkan nilai warna secara terprogram jika itu adalah referensi (tema)

116

Pertimbangkan ini:

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>

Jadi warna tema dirujuk oleh temanya. Bagaimana saya bisa mendapatkan theme_color (referensi) secara terprogram? Biasanya saya akan menggunakan getResources().getColor()tetapi tidak dalam kasus ini karena direferensikan!

Seraphim
sumber

Jawaban:

255

Ini harus melakukan pekerjaan itu:

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

Pastikan juga untuk menerapkan tema ke Aktivitas Anda sebelum memanggil kode ini. Salah satu penggunaan:

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

dalam manifes atau panggilan (sebelum Anda menelepon setContentView(int)):

setTheme(R.style.Theme_BlueTheme)

masuk onCreate().

Saya telah mengujinya dengan nilai-nilai Anda dan berhasil dengan sempurna.

Emanuel Moecklin
sumber
terima kasih Saya belum dapat mencoba solusi Anda karena saya mendapatkan kesalahan: stackoverflow.com/questions/17278244/… Mungkin Anda memiliki pengalaman dalam hal ini ...
Seraphim's
5
Bagaimanapun, dengan solusi Anda, saya mendapatkan 0 nilai warna (TypedValue {t = 0x0 / d = 0x0}) ... Saya tidak menggunakan decare-styleable, hanya referensi ke warna
Seraphim's
Apakah Anda menerapkan tema tersebut pada aktivitas Anda?
Emanuel Moecklin
5
Jika Anda tidak ingin menerapkan tema ke aktivitas, Anda bisa membuat ContextThemeWrappermenggunakan id tema dan kemudian mengambil tema darinya.
Ted Hopp
1
Metode ini berfungsi di Android X (perancangan material)
BlackBlind
43

Untuk menambah jawaban yang diterima, jika Anda menggunakan kotlin.

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

dan kemudian dalam aktivitas Anda, Anda dapat melakukannya

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

Bri6ko
sumber
2
oook, terima kasih untuk "integrasi". Saya tidak menggunakan kotlin tapi menarik.
Seraphim
5
Yah itu membuat TypedValue terlihat oleh dunia luar. Dan untuk warna Anda selalu ingin menyelesaikan deklarasi referensial, jadi saya punya ini: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = TypedValue().let { theme.resolveAttribute(attribute, it, true); it.data }(diformat dengan buruk di sini tapi tidak apa-apa)
milosmns
1
Penggunaannya akan seperti ini:val errorColor = context.getThemeColor(R.attr.colorError)
milosmns
Cara yang lebih universal, yang juga mengambil nilai default untuk ColorStateList: @ColorInt fun Context.getThemeColor(@AttrRes attribute: Int) = obtainStyledAttributes(intArrayOf(attribute)).use { it.getColor(0, Color.MAGENTA) }(dari Nick Butcher )
gmk57
Cara pamungkas, yang mengambil keseluruhan ColorStateList, bahkan jika itu mereferensikan atribut tema lain: fun Context.getThemeColor(@AttrRes attribute: Int): ColorStateList = TypedValue().let { theme.resolveAttribute(attribute, it, true); AppCompatResources.getColorStateList(this, it.resourceId) }(warna tunggal juga akan dibungkus ColorStateList).
gmk57
24

Ini berhasil untuk saya:

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

jika Anda ingin mengeluarkan hexstring darinya:

Integer.toHexString(color)
Angel Solis
sumber
Ini harus mengembalikan ColorRes, bukan ColorInt.
Miha_x64
Saya akhirnya menggunakan ini dengan getColorResource (color) dan tidak memanggil daur ulang.
Zeek Aran
2

Jika Anda ingin mendapatkan banyak warna, Anda dapat menggunakan:

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
sumber
2

Tambahkan ini ke build.gradle (app) Anda:

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

Dan tambahkan fungsi ekstensi ini di suatu tempat di kode Anda:

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

Berikut adalah metode utilitas Java ringkas yang mengambil banyak atribut dan mengembalikan larik bilangan bulat warna. :)

/**
 * @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
sumber
Java lebih baik dari Kotlin untuk ini?
IgorGanapolsky
@IgorGanapolsky Oh, sejujurnya saya tidak tahu. Saya membagikan kode saya karena saya tahu itu akan berguna bagi seseorang di luar sana! Saya tidak tahu Kotlin dan saya berasumsi bahwa Kotlin tidak akan membuatnya bekerja lebih baik, mungkin lebih sedikit baris kode! : P
varun
-1

Bagi mereka yang mencari referensi untuk ditarik Anda harus menggunakan falsediresolveRefs

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

Kilo
sumber
Apa variabel typedValue yang dirujuk?
BENN1TH
Apa yang dimaksud dengan tema variabel. *?
BENN1TH