Rozwiązanie wskazane przez @ (Ted Hopp) działa, ale wymaga niewielkiej korekty: w selektorze stany pozycji wymagają prefiksu „app:”, w przeciwnym razie inflater nie rozpozna poprawnie przestrzeni nazw i po cichu zawiedzie; przynajmniej tak się ze mną dzieje.
Pozwólcie, że opiszę tutaj całe rozwiązanie, z kilkoma szczegółami:
Najpierw utwórz plik „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>
Następnie zdefiniuj swoją klasę niestandardową. Na przykład może to być klasa „FoodButton” pochodząca z klasy „Button”. Będziesz musiał zaimplementować konstruktora; wdrożyć ten, który wydaje się być tym używanym przez inflatera:
public FoodButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
Oprócz klasy pochodnej:
private static final int[] STATE_FRIED = {R.attr.state_fried};
private static final int[] STATE_BAKED = {R.attr.state_baked};
Ponadto zmienne stanu:
private boolean mIsFried = false;
private boolean mIsBaked = false;
I kilka seterów:
public void setFried(boolean isFried) {mIsFried = isFried;}
public void setBaked(boolean isBaked) {mIsBaked = isBaked;}
Następnie zastąp funkcję „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;
}
Wreszcie najdelikatniejszy element tej układanki; selektor definiujący StateListDrawable, którego będziesz używać jako tła dla widgetu. To jest plik „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>
Zwróć uwagę na prefiks „app:”, podczas gdy w standardowych stanach Androida użyłbyś prefiksu „android:”. Przestrzeń nazw XML jest kluczowa dla poprawnej interpretacji przez inflater i zależy od typu projektu, w którym dodajesz atrybuty. Jeśli jest to aplikacja, zamień com.mydomain.mypackage na rzeczywistą nazwę pakietu aplikacji (bez nazwy aplikacji). Jeśli jest to biblioteka, musisz użyć „http://schemas.android.com/apk/res-auto” (i używać narzędzi w wersji 17 lub nowszej), w przeciwnym razie wystąpią błędy w czasie wykonywania.
Kilka uwag:
Wygląda na to, że nie musisz wywoływać funkcji "refreshDrawableState", przynajmniej rozwiązanie działa dobrze tak jak w moim przypadku
Aby użyć własnej klasy w pliku xml układu, musisz określić w pełni kwalifikowaną nazwę (np. Com.mydomain.mypackage.FoodButton)
Możesz dowolnie mieszać stany standardowe (np. Android: wciśnięty, android: włączony, android: wybrany) ze stanami niestandardowymi, aby przedstawić bardziej skomplikowane kombinacje stanów