たとえば、デフォルトボタンには、状態と背景画像の間に次の依存関係があります。
<?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
)、それでボタンの視覚的外観を動的に変更するためにそれを使用できますか?
@(Ted Hopp)で示されるソリューションは機能しますが、少し修正する必要があります。セレクターでは、アイテムの状態に「app:」プレフィックスが必要です。そうしないと、インフレータはネームスペースを正しく認識せず、サイレントに失敗します。少なくともこれは私に起こることです。
ここでソリューション全体を報告します。詳細を以下に示します。
まず、ファイル「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>
次に、カスタムクラスを定義します。たとえば、「Button」クラスから派生した「FoodButton」クラスの場合があります。コンストラクターを実装する必要があります。これを実装します。これは、インフレータで使用されるものと思われます。
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/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>
"app:"プレフィックスに注意してください。標準のAndroidでは、プレフィックス "Android:"を使用したことになります。XML名前空間は、インフレータによる正しい解釈に不可欠であり、属性を追加するプロジェクト。アプリケーションの場合は、com.mydomain.mypackageをアプリケーションの実際のパッケージ名(アプリケーション名は除く)に置き換えます。ライブラリの場合は、「 http://schemas.Android.com/apk/res-auto "(およびツールR17以降を使用している場合)またはランタイムエラーが発生します。
いくつかのメモ:
私の場合、少なくとも「refreshDrawableState」関数を呼び出す必要はないようです。少なくともソリューションは問題なく動作します
レイアウトxmlファイルでカスタムクラスを使用するには、完全修飾名(例:com.mydomain.mypackage.FoodButton)を指定する必要があります
より複雑な状態の組み合わせを表すために、標準状態(例:Android:pressed、Android:enabled、Android:selected)とカスタム状態を組み合わせることもできます
UIスレッド内でrefreshDrawableState
を呼び出すことを忘れないでください:
mHandler.post(new Runnable() {
@Override
public void run() {
refreshDrawableState();
}
});
すべてが正しく見えても、ボタンの状態が変わらない理由を理解するのに多くの時間がかかりました。