Bagaimana cara mereferensikan atribut gaya dari drawable?

96

Saya ingin memiliki 2 tema yang dapat dipilih untuk aplikasi saya. Untuk melakukan itu, saya mendefinisikan beberapa atribut, seperti ini:

 <attr format="color" name="item_background" />

Kemudian, saya membuat kedua tema tersebut, seperti ini:

  <style name="ThemeA">
     <item name="item_background">#123456</item>
 </style>

 <style name="ThemeB">
     <item name="item_background">#ABCDEF</item>
 </style>

Metode ini berfungsi dengan baik, memungkinkan saya membuat dan memodifikasi beberapa tema dengan mudah. Masalahnya adalah sepertinya itu hanya bisa digunakan di Views, dan bukan di Drawables .

Misalnya, mereferensikan nilai dari View di dalam layout berfungsi:

 <TextView android:background="?item_background" />

Tetapi melakukan hal yang sama di Drawable tidak:

 <shape android:shape="rectangle">
     <solid android:color="?item_background" />
 </shape>

Saya mendapatkan kesalahan ini saat menjalankan aplikasi:

    java.lang.UnsupportedOperationException: Can't convert to color: type=0x2

Jika alih-alih ?item_backgroundsaya menggunakan warna hardcode, itu berfungsi, tetapi itu tidak memungkinkan saya untuk menggunakan tema saya. Saya juga mencoba ?attr:item_background, tetapi hal yang sama terjadi.

Bagaimana saya bisa melakukan ini? Dan mengapa ini berfungsi di Views, tetapi tidak di Drawables? Saya tidak dapat menemukan batasan ini di mana pun dalam dokumentasi ...

MM.
sumber
Ini mungkin duplikat dari pertanyaan berikut: stackoverflow.com/questions/7529574/…
Paul Lammertsma
@ Martin M., apa yang Anda ketahui dengan ini?
pengguna123321
Ada solusi untuk itu? Saya menabrak tembok yang sama persis
Guillaume
Pertanyaan lain yang lebih baru di sini: stackoverflow.com/q/12115125/317889 Masalah yang sama. Urutkan itu di Google.
HGPB
3
Rupanya masalah ini telah diselesaikan dalam pratinjau Android L, seperti yang ditentukan di sini: code.google.com/p/android/issues/detail?id=26251
Bianca Daniciuc

Jawaban:

162

Menurut pengalaman saya, tidak mungkin mereferensikan atribut dalam drawable XML.
Untuk membuat tema Anda, Anda perlu:

  • Buat satu drawable XML per tema.
  • Sertakan warna yang dibutuhkan ke dalam drawable Anda secara langsung dengan @colortag atau format #RGB.

Buat atribut untuk drawable Anda di attrs.xml .

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <!-- Attributes must be lowercase as we want to use them for drawables -->
   <attr name="my_drawable" format="reference" />
</resources>

Tambahkan drawable Anda ke theme.xml .

<style name="MyTheme" parent="@android:style/Theme.NoTitleBar">
   <item name="my_drawable">@drawable/my_drawable</item>
</style>

Referensi drawable Anda dalam tata letak menggunakan atribut Anda.

<TextView android:background="?my_drawable" />
LG
sumber
20
Tampaknya, solusi ini masih diperlukan jika Anda ingin menjaga kompatibilitas ... Ya dari L sudah diperbaiki dan warna tema direferensikan dengan baik, tetapi kode yang sama berjalan pada perangkat pra-L yang berbeda dan sebenarnya referensi attr tidak berfungsi perangkat pra-L! LoL .. Jadi bagi saya itu tidak diperbaiki jika saya harus mempertahankan drawable yang berbeda.
Davideas
2
Saya berharap saya bisa memberi suara positif ini dua kali. Baru saja mencoba menyederhanakan bentuk saya untuk menggunakan referensi alih-alih #RGB yang di-hardcode dan mendapatkan kesalahan yang sama. Datang ke SO untuk mendapatkan solusi dan menemukan jawaban yang sama yang saya berikan suara positif 2 minggu yang lalu! (Telapak tangan)
Tiksi
2
Ini ninja super!
MariusBudin
4
ARGH! Ini harus menjadi prioritas utama bagi Google untuk melakukan perbaikan backport! Notasi? Attr-reference sangat berguna dan penting sehingga hampir mustahil untuk hidup tanpanya jika Anda memiliki banyak tema dalam sebuah aplikasi. Sekarang saya harus membuat tiga XML yang dapat digambar untuk setiap jenis tombol kustom!
Stephan Henningsen
2
Itu yang saya inginkan. solusi yang sangat sederhana dan bagus di <21 SDK.
Adnan Abdollah Zaki
20

Dimulai dengan lollipop(API 21) fitur ini didukung, lihat https://code.google.com/p/android/issues/detail?id=26251

Namun, jika Anda menargetkan perangkat tanpa lollipop, jangan gunakan, karena akan mogok, gunakan solusi di jawaban yang diterima.

marmor
sumber
Apakah ada kesempatan untuk menggunakan jenis pustaka dukungan untuk membuatnya bekerja pada API pra L?
Ivan
2
Tidak, pustaka dukungan adalah sekumpulan API yang dapat digunakan pada perangkat yang lebih lama, perubahan perilaku ini ada pada alat kompilator dan pembangunan, jadi tidak terkait dengan pustaka dukungan.
marmor
3
Tidak, di lollipop itu bukan fitur yang diterapkan, tetapi perbaikan bug yang mencolok. Dan bug serius pada saat itu.
Adrian Sicaru
Sial, saya pikir saya punya solusi bertema yang bagus. sekarang saya harus kembali dan membuat sekelompok drawable pemilih tombol.
filthy_wizard
4

Meskipun tidak mungkin untuk mereferensikan atribut gaya dari drawable pada perangkat pra-Lollipop , tetapi mungkin untuk daftar status warna. Anda bisa menggunakan metode AppCompatResources.getColorStateList (Context context, int resId) dari Android Support Library. Sisi negatifnya adalah Anda harus mengatur daftar status warna tersebut secara terprogram.

Ini adalah contoh yang sangat mendasar.

color / my_color_state.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_checked="true" android:color="?colorControlActivated" />
  <item android:color="?colorControlNormal" />
</selector>

Widget yang membutuhkan daftar status warna:

<RadioButton
  android:id="@+id/radio_button"
  android:text="My Radio" />

Dan yang terpenting:

ColorStateList csl = AppCompatResources.getColorStateList(context, R.color.my_color_state);    
RadioButton r = (RadioButton) findViewById(R.id.radio_button);
r.setTextColor(csl);

Yah, bukan cara yang paling elegan atau terpendek, tetapi inilah yang dilakukan oleh Perpustakaan Dukungan Android untuk membuatnya berfungsi pada versi Android yang lebih lama (pra-Lollipop).

Sayangnya, metode serupa untuk drawable tidak berfungsi dengan atribut gaya.

rubo
sumber
1

Saya menjawab pertanyaan yang sama di https://stackoverflow.com/a/59467269/3841352 tetapi saya akan mempostingnya di sini juga:

Saya mengalami masalah yang sama dan pada 2019 belum terselesaikan sehingga Anda tidak dapat memiliki atribut yang direferensikan di pemilih sebagai drawable. Saya akan membagikan solusi yang saya dapatkan untuk masalah ini karena saya tidak melihatnya diposting di sini. Saya menemukannya di komentar terakhir dari laporan bug .

Solusinya pada dasarnya adalah membuat sumber daya yang dapat digambar yang akan merujuk pada nilai atribut.

Untuk mengilustrasikan kasus Anda, solusinya adalah:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="?attr/colorPrimary" android:state_enabled="true" android:state_window_focused="false"/>
    <item android:drawable="?attr/colorPrimaryDark" android:state_pressed="true"/>
    <item android:drawable="@android:color/darker_gray" android:state_enabled="false"/>
    <item android:drawable="?attr/colorPrimary"/>
</selector>

Anda akan mengganti? attr / * untuk sumber daya yang dapat digambar:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/colorPrimaryDrawable" android:state_enabled="true" android:state_window_focused="false"/>
    <item android:drawable="@drawable/colorPrimaryDarkDrawable" android:state_pressed="true"/>
    <item android:drawable="@android:color/darker_gray" android:state_enabled="false"/>
    <item android:drawable="@drawable/colorPrimaryDrawable"/>
</selector>

Drawable akan didefinisikan sebagai:

drawable / colorPrimaryDrawable

<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
    <solid android:color="?attr/colorPrimary" />
</shape>

drawable / colorPrimaryDarkDrawable

<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle">
    <solid android:color="?attr/colorPrimaryDark" />
</shape>

Semoga membantu !!

Pol
sumber
0

Seperti yang dikatakan @marmor, ini sekarang didukung pada API 21. Tetapi bagi kami yang membutuhkan dukungan versi lama Android, Anda dapat menggunakan fitur ini. Menggunakan pustaka dukungan v7, Anda masih dapat menggunakannya di aplikasi dengan level SDK minimum hingga 7.

The AppCompatImageViewdi v7 Dukungan Perpustakaan Android memiliki implementasi bebas bug dari fitur ini. Cukup ganti penggunaan Anda ImageViewdengan AppCompatImageView.

Benjamin
sumber
2
Kedengarannya penuh harapan! Namun masalahnya ada pada bentuk Drawable, bukan pada View. Saya memiliki tampilan appcompat yang mereferensikan (sebagai latar belakang) sebuah bentuk yang menggunakan attr untuk mendapatkan warna bertema dan itu jatuh dengan kesalahan di atas pada <21. Apakah ada drawable appcompat yang saya lewatkan?
NeilS
Android 5.0.1 dari Huawei masih terpengaruh.
southerton