以编程方式替换选择器图像

116

我有一个ImageView,它的drawable图片资源设置为selector。我该如何以编程方式访问selector并更改高亮和非高亮状态下的图片?

这是selector的代码:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/iconSelector">
  <!-- pressed -->
  <item android:state_pressed="true" android:drawable="@drawable/btn_icon_hl" />
  <!-- focused -->
  <item android:state_focused="true" android:drawable="@drawable/btn_icon_hl" />
  <!-- default -->
  <item android:drawable="@drawable/btn_icon" />
</selector>

我希望能够用其他图片替换btn_icon_hlbtn_icon


有两个选择器并交换它们不是更容易吗? - bigstones
3
问题在于你最终可能会得到数百个 XML 文件。 - Emile
2个回答

246

据我所知(我自己尝试过类似的事情),在已经定义了StateListDrawable之后,没有办法修改单个状态。但是,您可以通过代码定义一个新的StateListDrawable:

StateListDrawable states = new StateListDrawable();
states.addState(new int[] {android.R.attr.state_pressed},
    getResources().getDrawable(R.drawable.pressed));
states.addState(new int[] {android.R.attr.state_focused},
    getResources().getDrawable(R.drawable.focused));
states.addState(new int[] { },
    getResources().getDrawable(R.drawable.normal));
imageView.setImageDrawable(states);

你可以随时保留其中两个,或者在需要时创建一个不同的。


2
实际上我找到了,是setImageDrawable()。非常感谢,它起作用了,而且还帮我节省了大约40个XML文件! - dropsOfJupiter
2
所以我有一个与此相关的注释。我希望你能回答。我在Custom Control内部设置了ImageView的选择器。自定义控件还具有选择器作为背景。因此,整个控件的选择器有效,而ImageView选择器无效。我做错了什么吗?有顺序要求吗? - dropsOfJupiter
3
我正在使用相同的代码。我指定在"new int[]{} state"中的图像总是保持不变。我错在哪里了? - KK_07k11A0585
1
我想你在“set selected”逻辑或getView()逻辑中做了一些设置所有奇数或偶数的事情。最好为此开始一个新问题。 - Kevin Coppock
1
小心,添加状态的顺序很重要! - Jleuleu
显示剩余8条评论

6

我遇到了同样的问题,为了解决它,我更进了一步。但唯一的问题是您不能在xml中指定NavStateListDrawable,所以您必须通过代码设置UI元素的背景。然后必须覆盖onStateChange方法,以确保每次更改主要可绘制对象的级别时,您还要更新子级别列表的级别。

构造NavStateListDrawable时,您必须传入要显示的图标的级别。

public class NavStateListDrawable extends StateListDrawable {

    private int level;

    public NavStateListDrawable(Context context, int level) {

        this.level = level;
        //int stateChecked = android.R.attr.state_checked;
        int stateFocused = android.R.attr.state_focused;
        int statePressed = android.R.attr.state_pressed;
        int stateSelected = android.R.attr.state_selected;

        addState(new int[]{ stateSelected      }, context.getResources().getDrawable(R.drawable.nav_btn_pressed));
        addState(new int[]{ statePressed      }, context.getResources().getDrawable(R.drawable.nav_btn_selected));
        addState(new int[]{ stateFocused      }, context.getResources().getDrawable(R.drawable.nav_btn_focused));

        addState(new int[]{-stateFocused, -statePressed, -stateSelected}, context.getResources().getDrawable(R.drawable.nav_btn_default));


    }

    @Override
    protected boolean onStateChange(int[] stateSet) {

        boolean nowstate = super.onStateChange(stateSet);

        try{
            LayerDrawable defaultDrawable = (LayerDrawable)this.getCurrent();


            LevelListDrawable bar2 =  (LevelListDrawable)defaultDrawable.findDrawableByLayerId(R.id.nav_icons);
            bar2.setLevel(level);
        }catch(Exception exception)
        {

        }

        return nowstate;
    }
}

对于我拥有的所有不同导航按钮可绘制状态,我有以下内容。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

   <item android:drawable="@drawable/top_bar_default" >

   </item>

    <item android:id="@+id/nav_icons" android:bottom="0dip">
        <level-list xmlns:android="http://schemas.android.com/apk/res/android">
            <item android:maxLevel="0" >
                <bitmap
                    android:src="@drawable/top_bar_icon_back"
                    android:gravity="center" />
            </item>
            <item android:maxLevel="1" >
                <bitmap
                    android:src="@drawable/top_bar_icon_nav"
                    android:gravity="center" />
            </item>
            <item android:maxLevel="2" >
                <bitmap
                    android:src="@drawable/top_bar_icon_settings"
                    android:gravity="center" />
            </item>
            <item android:maxLevel="3" >
                <bitmap
                    android:src="@drawable/top_bar_icon_search"
                    android:gravity="center" />
            </item>
        </level-list>

    </item>

</layer-list>

我原本想把这个发出来作为一个问题和答案,但是既然你已经问了这个问题,那么这里就是答案。注意,这样可以省去大量的xml文件定义。我从大约50-100个xml定义减少到了大约4个!

navstatelistdrawable 代码有效地使选择器 xml 多余。 - Emile
嗨,艾米丽, 有没有可能由于某种原因,可绘制对象作为按钮背景在第一次不显示。目前我遇到的问题是,我需要触摸按钮区域才能显示背景,或者切换并返回到活动中。(这仅在hdpi屏幕上发生,但在我的mdpi上运行正常)。我相信其他人也可能遇到这个问题。您的代码是否针对所有屏幕密度进行了测试? - shecodesthings
嗨,不,这是很久以前写的,而且当时只针对一种设备。我不确定会出现什么问题,因为据我所知,多个屏幕密度和布局不应该造成问题。 - Emile
谢谢,我不太清楚我做错了什么,但最终我只是有以下代码: buttonStates = new StateListDrawable(); buttonStates.addState(new int[]{statePressed}, ApplicationConstants.moduleImageLoader.findImageByName(drawable_pressed)); buttonStates.addState(new int[]{-stateFocused, -statePressed, -stateSelected}, ApplicationConstants.moduleImageLoader.findImageByName(drawable_normal)); - shecodesthings
1
这是我第一次看到必须使用负值来设置为 false 的状态。文档并不是很清楚。感谢您的提示! - eocanha

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