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


116

我有一个ImageView,其中有一个可绘制的图像资源设置为一个选择器。如何以编程方式访问选择器并更改突出显示和未突出显示状态的图像?

这是选择器的代码:

<?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_hl,并btn_icon与其他图像。


拥有两个选择器并交换它们会更容易吗?
bigstones 2011年

2
问题在于,您是否最终可能拥有数百个xml文件。
Emile

Answers:


244

据我所能找到的(我已经尝试做类似的事情),在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);

您可以只保留其中两个,也可以根据需要创建另一个。


1
我无法将其添加到图像视图。setState不可用。
dropOfJupiter 2011年

2
实际上我找到了它,它的setImageDrawable()非常感谢它的工作,并为我节省了大约40个xml文件!
dropOfJupiter 2011年

2
因此,我对此有另一个相关说明。我希望你能回答。我在自定义控件内的ImageView上设置了该选择器。自定义控件还具有一个选择器作为背景。因此,整个控件的选择器起作用,而ImageView选择器则不起作用。我做错什么了吗?有序列吗?
dropOfJupiter 2011年

1
别客气!是的,我不知道为什么要放setState,应该设置为setImageDrawable,是的。根据您的其他问题,我建议您发布一个新问题,其中包含您的自定义控件及其选择器的代码,但不确定答案。
凯文·科波克

3
我正在使用相同的代码。我在----> new int [] {}状态中指定的图像始终保持不变。我在哪里错了?
KK_07k11A0585 2012年

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

嗨,emilie,是否有可能由于任何原因而将可绘制对象作为按钮背景第一次显示出来。目前,我遇到的问题是我需要触摸按钮的区域以显示背景,或者关闭并切换回活动。(这仅在hdpi屏幕上发生,但在我的mdpi上工作正常)。我相信其他人也可能有这个问题。您的代码是否针对所有屏幕密度进行了测试?
ryvianstyron,2012年

嗨,不,这是很早以前写的,而且当时只适用于一台设备。我不确定会出现哪种问题,尽管据我所知,多个屏幕的密度和布局应该不会出现问题。
Emile 2012年

谢谢,我不太清楚自己在做什么,但最后我只有以下内容: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));
ryvianstyron '11

1
这是我第一次看到必须将负值用于设置为false的状态。该文档对此不太清楚。谢谢你的提示!
eocanha 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.