2010-12-02 38 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(); 
    } 
}); 

花了我很多时间来弄清楚为什么我的按钮不改变其状态,即使一切看起来正确的。

相关问题