Giải pháp được chỉ định bởi @ (Ted Hopp) hoạt động, nhưng cần một chút hiệu chỉnh: trong bộ chọn, các trạng thái mục cần một tiền tố "ứng dụng:", nếu không, bộ lọc sẽ không nhận ra không gian tên chính xác và sẽ thất bại trong âm thầm; ít nhất đây là những gì xảy ra với tôi.
Cho phép tôi báo cáo ở đây toàn bộ giải pháp, với một số chi tiết khác:
Đầu tiên, tạo tệp "res / value / 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>
Sau đó xác định lớp tùy chỉnh của bạn. Ví dụ, nó có thể là một lớp "FoodButton", xuất phát từ lớp "Nút". Bạn sẽ phải thực hiện một hàm tạo; thực hiện cái này, cái mà dường như là cái được sử dụng bởi Inflater:
public FoodButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
Trên đầu lớp dẫn xuất:
private static final int[] STATE_FRIED = {R.attr.state_fried};
private static final int[] STATE_BAKED = {R.attr.state_baked};
Ngoài ra, các biến trạng thái của bạn:
private boolean mIsFried = false;
private boolean mIsBaked = false;
Và một vài setters:
public void setFried(boolean isFried) {mIsFried = isFried;}
public void setBaked(boolean isBaked) {mIsBaked = isBaked;}
Sau đó, ghi đè chức năng "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;
}
Cuối cùng, mảnh tinh tế nhất của câu đố này; bộ chọn xác định StateListDrawable mà bạn sẽ sử dụng làm nền cho widget của mình. Đây là tệp "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>
Lưu ý tiền tố "ứng dụng:", trong khi với các trạng thái Android tiêu chuẩn, bạn sẽ sử dụng tiền tố "android:". Không gian tên XML là rất quan trọng để giải thích chính xác bởi người thổi phồng và phụ thuộc vào loại dự án mà bạn đang thêm thuộc tính. Nếu đó là một ứng dụng, hãy thay thế com.mydomain.mypackage bằng tên gói thực tế của ứng dụng của bạn (loại trừ tên ứng dụng). Nếu đó là thư viện, bạn phải sử dụng "http://schemas.android.com/apk/res-auto" (và đang sử dụng Công cụ R17 trở lên) nếu không bạn sẽ gặp lỗi thời gian chạy.
Một vài lưu ý:
Có vẻ như bạn không cần phải gọi hàm "refreshDrawableState", ít nhất là giải pháp hoạt động tốt như trong trường hợp của tôi
Để sử dụng lớp tùy chỉnh của bạn trong tệp xml bố cục, bạn sẽ phải chỉ định tên đủ điều kiện (ví dụ: com.mydomain.mypackage.FoodButton)
Bạn có thể như weel trộn các trạng thái tiêu chuẩn (ví dụ: android: nhấn, android: enable, android: đã chọn) với các trạng thái tùy chỉnh, để thể hiện các kết hợp trạng thái phức tạp hơn