Программная замена изображений селектора

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другие изображения.

dropsOfJupiter
источник
не было бы проще иметь два селектора и менять их местами?
bigstones
2
Проблема в том, что вы можете получить сотни файлов xml.
Эмиль

Ответы:

245

Насколько мне удалось найти (я сам пробовал сделать что-то подобное), нет возможности изменить одно состояние после того, как 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 на нем недоступен.
dropsOfJupiter
2
на самом деле я нашел его, его setImageDrawable () Спасибо большое, он сработал и спас мне около 40 файлов xml!
dropsOfJupiter
2
Так что у меня есть еще одно примечание по этому поводу. Я надеялся, что ты ответишь. У меня этот селектор установлен в ImageView, который находится внутри пользовательского элемента управления. Пользовательский элемент управления также имеет селектор в качестве фона. Таким образом, селектор всего элемента управления работает, а селектор ImageView - нет. Что-то я делаю не так? Есть последовательность?
dropsOfJupiter
1
Пожалуйста! Да, я не знаю, почему я поставил setState, должен быть setImageDrawable, вы правы. Что касается вашего другого вопроса, я бы предложил опубликовать новый вопрос с кодом для вашего настраиваемого элемента управления и его селектором, я не уверен в ответе на это.
Кевин Коппок
3
я использую тот же код. всегда остается изображение, которое я указал в состоянии ----> new int [] {}. где я был не прав ??
KK_07k11A0585
6

У меня была та же проблема, и я пошел дальше, чтобы ее решить. Однако единственная проблема заключается в том, что вы не можете указать NavStateListDrawable в xml, поэтому вам нужно установить фон своего элемента пользовательского интерфейса с помощью кода. Затем необходимо переопределить метод 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 !.

Emile
источник
Код navstatelistdrawable эффективно делает селектор xml избыточным.
Эмиль
Привет, Эмили! Есть ли вероятность, что рисунки в качестве фона кнопки не появятся в первый раз по какой-либо причине. В настоящее время у меня возникает проблема, когда мне нужно коснуться области кнопки, чтобы отобразился фон, или выключить и вернуться к активности. (Это происходит только на экране hdpi, но отлично работает на моем mdpi). Я считаю, что у других тоже может быть эта проблема. Ваш код протестирован для всех плотностей экрана?
ryvianstyron
Привет, нет, это было написано довольно давно и тогда было только для одного устройства. Я не уверен, какая проблема может возникнуть, хотя, насколько мне известно, несколько плотностей экрана и макетов не должны представлять проблемы.
Emile
Спасибо, я не совсем понимаю, что делал не так, но в итоге у меня было только следующее: buttonStates = new StateListDrawable (); buttonStates.addState (новый int [] {statePressed}, ApplicationConstants.moduleImageLoader.findImageByName (drawable_pressed)); buttonStates.addState (новый int [] {- ​​stateFocused, -statePressed, -stateSelected}, ApplicationConstants.moduleImageLoader.findImageByName (drawable_normal));
ryvianstyron 09
1
Это первое место, где я вижу, что отрицательные значения должны использоваться для состояний, установленных на false. В документации об этом не очень ясно. Спасибо за чаевые!
eocanha 02