Android:如何在程序中更新选择器(StateListDrawable)

66
我想通过编程方式更新按钮的选择器。
我可以使用下面给出的xml文件来实现这一点。
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:state_enabled="false"
         android:drawable="@drawable/btn_off" />
   <item android:state_pressed="true"
         android:state_enabled="true" 
         android:drawable="@drawable/btn_off" />
   <item android:state_focused="true"
         android:state_enabled="true" 
         android:drawable="@drawable/btn_on" />
   <item android:state_enabled="true" 
         android:drawable="@drawable/btn_on" />
</selector>

我希望以编程方式做同样的事情。我尝试了以下类似的方法:

private StateListDrawable setImageButtonState(int index)
{
    StateListDrawable states = new StateListDrawable();

    states.addState(new int[] {android.R.attr.stateNotNeeded},R.drawable.btn_off); 
    states.addState(new int[] {android.R.attr.state_pressed, android.R.attr.state_enabled},R.drawable.btn_off);
    states.addState(new int[] {android.R.attr.state_focused, android.R.attr.state_enabled},R.drawable.btn_on);
    states.addState(new int[] {android.R.attr.state_enabled},R.drawable.btn_on);

    return states;
}

但它没有起作用。

如何以编程方式设置 android:state_enabled="false"android:state_enabled="true"

5个回答

124
您需要使用所需状态的负值。 例如:
states.addState(new int[] {-android.R.attr.state_enabled},R.drawable.btn_disabled);

注意在android.R.attr.state_enabled之前的"-"符号。


1
在我的情况下不起作用,它只是为启用状态设置可绘制对象...我在这里做错了什么,代码完全相同。 - Yogesh Maheshwari
@androiddeveloper 我假设 "-" 是用来定义禁用状态的负值,因为你无法以其他方式定义它。(没有 android.R.attr.state_disabled)。 - ingh.am
2
@ing0 所以这是针对“false”状态的值?我认为这是一个糟糕的API选择,因为它不直观,而且如果有一天它将超过2个值(真和假)...无论如何,谢谢。 - android developer
@androiddeveloper 我不确定,因为我还没有测试过,但我认为是这样的。是的,我同意它并不直观。 - ingh.am
1
@Osi,Lollipop对我来说无法工作,有什么建议吗? - Defuera
显示剩余4条评论

13

虽然回复有些晚了,但如果还有其他人在尝试以编程方式设置StateListDrawable时遇到问题。就像XML文件一样,将状态按照特定顺序添加到StateListDrawable中是很重要的。

例如,以下内容会按预期工作:

StateListDrawable sld = new StateListDrawable();
sld.addState(new int[] { android.R.attr.state_pressed }, new ColorDrawable(Color.GRAY));
sld.addState(new int[] {}, new ColorDrawable(Color.GREEN));

这段文字不会改变:

StateListDrawable sld = new StateListDrawable();
sld.addState(new int[] {}, new ColorDrawable(Color.GREEN));
sld.addState(new int[] { android.R.attr.state_pressed }, new ColorDrawable(Color.GRAY));

2
似乎需要将默认状态设置为LAST。这毫无意义,但是这样做确实使其正常工作... 摇头... - Aggressor
XML状态列表可绘制对象也是一样的,不是吗?默认值必须始终位于最后。我猜这个顺序将用于检测哪个模式首先匹配,然后将其用作源。 - Robin Vinzenz

7

评论需要足够的声望,但是被接受的答案对我没有用。

我的目标是让设计师在某些按钮上设置启用、禁用和按下时的背景颜色。我打算让他们用来测试不同显示器上的颜色。

我注意到一些其他人也提到它对他们也没用。

需要定义的状态是:

  • 未按下且启用,这是当按钮启用且未按下时所看到的状态。
  • 已按下且启用,这是当按钮已按下并启用时所看到的状态
  • 未启用。这是当按钮被禁用时所看到的状态

以下是一些代码,可以让您了解这些状态。 我使用Color.Parse()生成颜色的整数,然后将它们传递给此方法以获取StateListDrawable。

private StateListDrawable createDrawable(int enabled, int pressed, int disabled) {
  StateListDrawable stateListDrawable = new StateListDrawable();

  stateListDrawable.addState(new int[] { -android.R.attr.state_pressed, android.R.attr.state_enabled }, new ColorDrawable(enabled));
  stateListDrawable.addState(new int[] { android.R.attr.state_pressed, android.R.attr.state_enabled }, new ColorDrawable(pressed));
  stateListDrawable.addState(new int[] { -android.R.attr.state_enabled }, new ColorDrawable(disabled));

  return stateListDrawable;
}

@androidAhmed 当我建立这个应用时,我使用了View#setBackground(Drawable background)方法。https://developer.android.com/reference/android/view/View#setBackground(android.graphics.drawable.Drawable) - Voski

7
我将回答您的问题“如何在程序中更新按钮的选择器?” 我建议使用一个带有嵌入式ImageView和TextView的LinearLayout来替换按钮。这样做有许多好处,特别是如果您稍后决定自定义视图。这种转换不会导致任何功能损失。您仍然可以像按钮一样附加相同的事件监听器,但可以避免按钮/选项卡的样式问题。以下是layout.xml中相关的代码。
    <LinearLayout 
        android:id="@+id/button"
        style="@style/ButtonStyle">
        <ImageView 
            android:id="@+id/background"
            android:src="@drawable/custom_image"/>
        <TextView 
            style="@style/TextStyle"
            android:text="Custom Button"
            android:id="@+id/text"/>
    </LinearLayout> 

接下来,我有一个名为custom_image.xml的选择器文件,位于drawable文件夹中。以下是选择器文件的内容:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/disabled_img"     android:state_enabled="false" />
    <item android:drawable="@drawable/unselected_img"     android:state_selected="false" />
    <item android:drawable="@drawable/selected_img"     android:state_selected="true" />
</selector>

三个源图像文件(disabled_img.png、unselected_img.png、selected_img.png)也位于drawable文件夹中。

现在回到你的Java代码。有许多原因不需要使用奇怪的StateListDrawable垃圾。首先,它看起来很丑,难以维护。但最重要的是,它违反了将逻辑与表现分开的原则。如果你在Java代码中管理你的可绘制资源,你知道你正在做一些根本错误的事情。

这是我提出的替代方案。每当你想要选择按钮时,只需在其中插入这个一行代码:

((LinearLayout)findViewById(R.id.button)).setSelected(true);

或者,每当你想让按钮处于禁用状态时,这里有另一个一行代码:

((ImageView)findViewById(R.id.background)).setEnabled(false);

请注意,在此示例中,我正在指定LinearLayout内部的ImageView的禁用状态。由于某种原因,每当您更改LinearLayout的启用/禁用状态时,选择器都不会被触发。如果您在ImageView上执行此操作,则可以正常工作。

1
这是一个非答案。问题是如何在程序中设置statedrawables,而您解释了如何在XML中完成,这已经在问题中展示过了。 - Cross_

0

我不知道你是如何添加StateListDrawable的,因为代码不在这里。但一定要检查文档并添加setState()

你可以从视图中设置属性,例如yourView.setEnabled(true)

希望这有所帮助


yourView.setEnabled(true); 这段代码是用来启用或禁用的。我想为启用/禁用状态设置我的图像。 - Mani
是的,你需要启用或禁用“视图”以触发图像的状态,它们是相互关联的。如果“视图”没有经历这种行为,你不能也不应该需要显示图像的启用/禁用状态。 - raukodraug
他正在询问如何使用状态数组参数使他的代码正常工作。 - Tyler Zale
1
相关问题:https://dev59.com/Qm445IYBdhLWcg3wytIU - Tyler Zale

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接