例如,默认按钮在其状态和背景图像之间具有以下依赖关系:
<?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
这样的smth),那么我可以用它来动态更改我的按钮视觉外观?
答案 0 :(得分:242)
@(Ted Hopp)指出的解决方案有效,但需要稍微纠正:在选择器中,项状态需要一个“app:”前缀,否则inflater将无法正确识别命名空间,并将无声地失败;至少这是发生在我身上的事情。
请允许我在此报告整个解决方案,并提供更多详细信息:
首先,创建文件“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>
然后定义您的自定义类。例如,它可能是一个类“FoodButton”,派生自“Button”类。你将不得不实现一个构造函数;实现这个,这似乎是inflater使用的那个:
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命名空间对于inflater的正确解释至关重要,并且取决于您添加属性的项目类型。如果是应用程序,请将 com.mydomain.mypackage 替换为应用程序的实际程序包名称(不包括应用程序名称)。如果是库,则必须使用“http://schemas.android.com/apk/res-auto”(并使用Tools R17或更高版本),否则会出现运行时错误。
几点说明:
看来你不需要调用“refreshDrawableState”函数,至少解决方案效果不错,在我的情况下
要在布局xml文件中使用自定义类,您必须指定完全限定名称(例如com.mydomain.mypackage.FoodButton)
你可以用自定义状态混淆标准状态(例如android:press,android:enabled,android:selected),以表示更复杂的状态组合
答案 1 :(得分:9)
This thread显示了如何向按钮等添加自定义状态。 (如果您在浏览器中看不到新的Google网上论坛,则会有一个帖子here的副本。)
答案 2 :(得分:5)
请不要忘记在UI线程中调用refreshDrawableState
:
mHandler.post(new Runnable() {
@Override
public void run() {
refreshDrawableState();
}
});
我花了很多时间弄清楚为什么我的按钮没有改变它的状态,即使一切看起来都正确。