Ersetzen Sie die Auswahlbilder programmgesteuert

116

Ich habe eine ImageView, für die eine Zeichenressource auf einen Selektor festgelegt ist. Wie greife ich programmgesteuert auf den Selektor zu und ändere die Bilder des hervorgehobenen und nicht hervorgehobenen Zustands?

Hier ist ein Auswahlcode:

<?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>

Ich möchte in der Lage sein, btn_icon_hlund btn_icondurch andere Bilder zu ersetzen .

Tropfen von Jupiter
quelle
Wäre es nicht einfacher, zwei Selektoren zu haben und sie auszutauschen?
Bigstones
2
Das Problem dabei ist, dass Sie am Ende Hunderte von XML-Dateien haben können.
Emile

Antworten:

244

Soweit ich feststellen konnte (ich habe versucht, etwas Ähnliches selbst zu tun), gibt es keine Möglichkeit, einen einzelnen Status zu ändern, nachdem StateListDrawable bereits definiert wurde. Sie können jedoch einen NEUEN durch Code definieren:

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);

Und Sie können einfach zwei davon zur Hand haben oder nach Bedarf ein anderes erstellen.

Kevin Coppock
quelle
1
Ich konnte dies nicht zu einer Bildansicht hinzufügen. setState ist darauf nicht verfügbar.
Tropfen von Jupiter
2
Eigentlich habe ich es gefunden, sein setImageDrawable () Vielen Dank, es hat funktioniert und mir ungefähr 40 XML-Dateien gespeichert!
Tropfen von Jupiter
2
Ich habe also noch einen Hinweis dazu. Ich hatte gehofft, Sie können antworten. Ich habe diesen Selektor in der ImageView festgelegt, die sich im benutzerdefinierten Steuerelement befindet. Benutzerdefinierte Steuerung hat auch einen Selektor als Hintergrund. Der Selektor des gesamten Steuerelements funktioniert also, der ImageView-Selektor nicht. Gibt es etwas, was ich falsch mache? Gibt es eine Sequenz?
Tropfen von Jupiter
1
Bitte! Ja, ich weiß nicht, warum ich setState gesetzt habe, sollte setImageDrawable sein, du hast recht. Gemäß Ihrer anderen Frage würde ich vorschlagen, eine neue Frage mit dem Code für Ihr benutzerdefiniertes Steuerelement und dessen Auswahl zu veröffentlichen. Ich bin mir bei der Antwort darauf nicht sicher.
Kevin Coppock
3
Ich benutze den gleichen Code. Es bleibt immer das Bild, das ich in ----> new int [] {} state angegeben habe. Wo habe ich mich geirrt?
KK_07k11A0585
6

Ich hatte das gleiche Problem und ging noch einen Schritt weiter, um es zu lösen. Das einzige Problem ist jedoch, dass Sie NavStateListDrawable nicht in XML angeben können, sodass Sie den Hintergrund Ihres UI-Elements über Code festlegen müssen. Die onStateChange-Methode muss dann überschrieben werden, um sicherzustellen, dass Sie bei jeder Änderung der Ebene des Hauptzeichens auch die Ebene der Liste der untergeordneten Ebenen aktualisieren.

Beim Erstellen des NavStateListDrawable müssen Sie die Ebene des Symbols übergeben, das Sie anzeigen möchten.

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;
    }
}

Für all die verschiedenen Zeichnungszustände der Navigationsschaltfläche habe ich ungefähr Folgendes.

<?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>

Ich wollte dies als Frage und Antwort posten, aber da Sie genau diese Frage gestellt haben, können Sie loslegen. Beachten Sie, dass Sie dadurch eine Menge XML-Dateidefinitionen sparen. Ich ging von ungefähr 50-100 XML-Definitionen auf ungefähr 4!.

Emile
quelle
Der navstatelistdrawable-Code macht die Selector-XML effektiv überflüssig.
Emile
Hallo Emilie, gibt es eine Möglichkeit, dass Drawables als Schaltflächenhintergrund aus irgendeinem Grund nicht zum ersten Mal angezeigt werden? Derzeit tritt das Problem auf, dass ich den Bereich der Schaltfläche berühren muss, damit der Hintergrund angezeigt wird, oder ausschalten und zur Aktivität zurückkehren muss. (Dies geschieht nur auf einem HDPI-Bildschirm, funktioniert aber auf meinem MDPI einwandfrei). Ich glaube, andere haben dieses Problem möglicherweise auch. Wird Ihr Code auf alle Bildschirmdichten getestet?
Ryvianstyron
Hallo, nein, dies wurde vor einiger Zeit geschrieben und war zu der Zeit nur für ein Gerät. Ich bin mir nicht sicher, welche Art von Problem auftreten könnte, obwohl mir bekannt ist, dass mehrere Bildschirmdichten und Layouts kein Problem darstellen sollten.
Emile
Danke Ich weiß nicht genau, was ich falsch gemacht habe, aber am Ende hatte ich nur folgendes: 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
1
Dies ist der erste Ort, an dem ich sehe, dass negative Werte für Zustände verwendet werden müssen, die auf false gesetzt sind. Die Dokumentation ist darüber nicht sehr klar. Danke für den Tipp!
Eocanha