2010-12-02 70 views
100

例如,默認按鈕都有其狀態和背景圖像之間的以下相關:如何添加自定義按鈕狀態

<?xml version="1.0" encoding="utf-8"?> 
<selector xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:state_window_focused="false" android:state_enabled="true" 
     android:drawable="@drawable/btn_default_normal" /> 
    <item android:state_window_focused="false" android:state_enabled="false" 
     android:drawable="@drawable/btn_default_normal_disable" /> 
    <item android:state_pressed="true" 
     android:drawable="@drawable/btn_default_pressed" /> 
    <item android:state_focused="true" android:state_enabled="true" 
     android:drawable="@drawable/btn_default_selected" /> 
    <item android:state_enabled="true" 
     android:drawable="@drawable/btn_default_normal" /> 
    <item android:state_focused="true" 
     android:drawable="@drawable/btn_default_normal_disable_focused" /> 
    <item 
     android:drawable="@drawable/btn_default_normal_disable" /> 
</selector> 

我如何定義自己的自定義狀態(水木清華像android:state_custom),這樣的話我可以用它來動態改變我的按鈕視覺外觀?

+0

我想爲EditText視圖添加額外的狀態以確定兩個密碼框匹配時是否顯示一個複選標記。 – schwiz 2010-12-23 22:07:53

回答

222

@(Ted Hopp)指示的解決方案有效,但需要稍微更正:在選擇器中,項目狀態需要一個「app:」前綴,否則inflater將無法正確識別名稱空間,並且會默默失敗;至少這是發生在我身上的事情。

請允許我在這裏報告的整體解決方案,與一些更多的細節:

首先,創建文件 「RES /價值/ 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> 

然後定義您的自定義類。例如,它可能是一個「FoodButton」類,從類「Button」派生。你將不得不實現一個構造函數;實現這一個,這似乎是由充氣使用的一個:

public FoodButton(Context context, AttributeSet attrs) { 
    super(context, attrs); 
} 

在派生類的頂部:

private static final int[] STATE_FRIED = {R.attr.state_fried}; 
private static final int[] STATE_BAKED = {R.attr.state_baked}; 

此外,您的狀態變量:

private boolean mIsFried = false; 
private boolean mIsBaked = false; 

而且幾個安裝人員:

public void setFried(boolean isFried) {mIsFried = isFried;} 
public void setBaked(boolean isBaked) {mIsBaked = isBaked;} 

然後覆蓋函數「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; 
} 

最後,這個難題最細膩的一塊;選擇器定義您將用作窗口小部件背景的StateListDrawable。這是文件 「RES /繪製/ 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> 

公告的 「應用程序:」 前綴,而使用標準Android狀態就要使用前綴 「機器人」。 XML名稱空間對於inflater的正確解釋至關重要,並取決於您添加屬性的項目類型。如果是應用程序,請將com.mydomain.mypackage替換爲應用程序的實際軟件包名稱(不包括應用程序名稱)。如果它是一個庫,則必須使用「http://schemas.android.com/apk/res-auto」(並且使用Tools R17或更高版本),否則您將收到運行時錯誤。

有兩點要注意:

  • 看來你並不需要調用「refreshDrawableState」功能,至少解決方案的工作以及是,在我的情況

  • 爲了要在佈局xml文件中使用您的自定義類,您必須指定完全限定的名稱(例如com。mydomain.mypackage.FoodButton)

  • 您可以根據WEEL混淆標準狀態(例如機器人:按下時,機器人:啓用,機器人:選擇)自定義狀態,以表示更復雜的狀態組合

9

This thread顯示如何將自定義狀態添加到按鈕等。 (如果您在瀏覽器中看不到新的Google羣組,則有here線程的副本。)

+0

+1非常感謝,泰德!現在麻煩來了,所以我沒有去實際的實施。但是,如果我的客戶再次回到這裏,我會嘗試你指向我的方式。 – 2010-12-21 08:23:06

+0

看起來完全像我所需要的,但是,我的自定義狀態的狀態列表drawables沒有改變,我一定是錯過了... – schwiz 2010-12-24 06:10:22

5

請不要忘記UI線程中調用refreshDrawableState

mHandler.post(new Runnable() { 
    @Override 
    public void run() { 
     refreshDrawableState(); 
    } 
}); 

花了我很多時間來弄清楚爲什麼我的按鈕不改變其狀態,即使一切看起來正確的。

相關問題