Solusi yang ditunjukkan oleh @ (Ted Hopp) berfungsi, tetapi membutuhkan sedikit koreksi: di pemilih, status item memerlukan awalan "app:", jika tidak, inflater tidak akan mengenali namespace dengan benar, dan akan gagal secara diam-diam; setidaknya inilah yang terjadi pada saya.
Izinkan saya melaporkan di sini seluruh solusi, dengan beberapa perincian lebih lanjut:
Pertama, buat file "res / values / attrs.xml":
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="food">
<attr name="state_fried" format="boolean" />
<attr name="state_baked" format="boolean" />
</declare-styleable>
</resources>
Kemudian tentukan kelas khusus Anda. Misalnya, itu mungkin kelas "FoodButton", berasal dari kelas "Tombol". Anda harus mengimplementasikan konstruktor; mengimplementasikan yang ini, yang tampaknya menjadi yang digunakan oleh inflater:
public FoodButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
Di atas kelas turunan:
private static final int[] STATE_FRIED = {R.attr.state_fried};
private static final int[] STATE_BAKED = {R.attr.state_baked};
Juga, variabel status Anda:
private boolean mIsFried = false;
private boolean mIsBaked = false;
Dan beberapa setter:
public void setFried(boolean isFried) {mIsFried = isFried;}
public void setBaked(boolean isBaked) {mIsBaked = isBaked;}
Kemudian timpa fungsi "onCreateDrawableState":
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
if (mIsFried) {
mergeDrawableStates(drawableState, STATE_FRIED);
}
if (mIsBaked) {
mergeDrawableStates(drawableState, STATE_BAKED);
}
return drawableState;
}
Akhirnya, bagian paling rumit dari teka-teki ini; pemilih mendefinisikan StateListDrawable yang akan Anda gunakan sebagai latar belakang untuk widget Anda. Ini adalah file "res / drawable / food_button.xml":
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.mydomain.mypackage">
<item
app:state_baked="true"
app:state_fried="false"
android:drawable="@drawable/item_baked" />
<item
app:state_baked="false"
app:state_fried="true"
android:drawable="@drawable/item_fried" />
<item
app:state_baked="true"
app:state_fried="true"
android:drawable="@drawable/item_overcooked" />
<item
app:state_baked="false"
app:state_fried="false"
android:drawable="@drawable/item_raw" />
</selector>
Perhatikan awalan "app:", sedangkan dengan status android standar Anda akan menggunakan awalan "android:". Namespace XML sangat penting untuk interpretasi yang benar oleh inflater dan tergantung pada jenis proyek di mana Anda menambahkan atribut. Jika itu adalah aplikasi, ganti com.mydomain.mypackage dengan nama paket aplikasi Anda yang sebenarnya (tidak termasuk nama aplikasi). Jika perpustakaan, Anda harus menggunakan "http://schemas.android.com/apk/res-auto" (dan menggunakan Tools R17 atau yang lebih baru) atau Anda akan mendapatkan kesalahan runtime.
Beberapa catatan:
Tampaknya Anda tidak perlu memanggil fungsi "refreshDrawableState", setidaknya solusinya berfungsi dengan baik, dalam kasus saya
Untuk menggunakan kelas khusus Anda dalam file xml tata letak, Anda harus menentukan nama yang sepenuhnya memenuhi syarat (mis. Com.mydomain.mypackage.FoodButton)
Anda dapat sebagai negara campuran standar (mis. Android: ditekan, android: diaktifkan, android: dipilih) dengan status khusus, untuk mewakili kombinasi keadaan yang lebih rumit