Sostituisci le immagini del selettore a livello di codice


116

Ho un ImageView che ha una risorsa immagine disegnabile impostata su un selettore. Come si accede al selettore a livello di programmazione e si modificano le immagini dello stato evidenziato e non evidenziato?

Ecco un codice del selettore:

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

Voglio essere in grado di sostituire btn_icon_hle btn_iconcon altre immagini.


non sarebbe più facile avere due selettori e scambiarli?
bigstones

2
Il problema è che puoi finire con centinaia di file xml.
Emile

Risposte:


244

Per quanto sono riuscito a trovare (ho provato a fare qualcosa di simile io stesso), non c'è modo di modificare un singolo stato dopo che StateListDrawable è già stato definito. Puoi comunque definirne uno NUOVO tramite codice:

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

E potresti semplicemente tenerne due a portata di mano o crearne uno diverso quando ne hai bisogno.


1
Non sono stato in grado di aggiungerlo a una visualizzazione immagine. setState non è disponibile su di esso.
dropsOfJupiter

2
in realtà l'ho trovato, è setImageDrawable () Grazie mille ha funzionato e mi ha salvato circa 40 file xml!
dropsOfJupiter

2
Quindi ho un'altra nota correlata a questo. Speravo potessi rispondere. Ho questo selettore impostato su ImageView che si trova all'interno del controllo personalizzato. Il controllo personalizzato ha anche un selettore come sfondo. Quindi il selettore dell'intero controllo funziona, mentre il selettore ImageView no. C'è qualcosa che sto facendo di sbagliato? C'è una sequenza?
dropsOfJupiter

1
Prego! Sì, non so perché ho messo setState, dovrebbe essere setImageDrawable, hai ragione. Come per l'altra tua domanda, suggerirei di pubblicare una nuova domanda con il codice per il tuo controllo personalizzato e il suo selettore, non sono sicuro della risposta a questo.
Kevin Coppock

3
sto usando lo stesso codice. rimane sempre l'immagine che ho specificato nello stato ----> new int [] {}. dove ho sbagliato ??
KK_07k11A0585

6

Ho avuto lo stesso problema e ho fatto un ulteriore passo avanti per risolverlo. L'unico problema tuttavia è che non puoi specificare NavStateListDrawable in xml, quindi devi impostare lo sfondo del tuo elemento dell'interfaccia utente tramite codice. Il metodo onStateChange deve quindi essere sovrascritto per garantire che ogni volta che il livello del drawable principale viene modificato, si aggiorna anche il livello dell'elenco dei livelli figlio.

Quando si costruisce il NavStateListDrawable è necessario passare il livello dell'icona che si desidera visualizzare.

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

Per tutti i diversi stati disegnabili dei pulsanti di navigazione ho qualcosa di simile al seguente.

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

Volevo postare questo come una domanda e una risposta, ma visto che hai posto proprio la domanda, ecco qui. Nota, questo ti fa risparmiare un sacco di definizioni di file xml. sono passato da circa 50-100 definizioni xml a circa 4 !.


Il codice navstatelistdrawable rende effettivamente ridondante il selettore xml.
Emile

Ciao emilie, c'è la possibilità che i drawable come sfondo di un pulsante non vengano visualizzati la prima volta per qualsiasi motivo. Attualmente sto riscontrando il problema in cui devo toccare l'area del pulsante per far apparire lo sfondo, oppure spegnere e tornare all'attività. (Questo accade solo su uno schermo hdpi, ma funziona bene sul mio mdpi). Credo che anche altri possano avere questo problema. Il tuo codice è testato per tutte le densità dello schermo?
ryvianstyron

Ciao, no, questo è stato scritto molto tempo fa ed era solo per un dispositivo alla volta. Non sono sicuro del tipo di problema che potrebbe verificarsi, anche se per quanto ne so più densità e layout dello schermo non dovrebbero presentare un problema.
Emile

Grazie non so bene cosa stavo facendo di sbagliato ma alla fine ho avuto solo il seguente: 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
Questo è il primo punto in cui vedo che è necessario utilizzare valori negativi per gli stati impostati su false. La documentazione non è molto chiara al riguardo. Grazie per il consiglio!
eocanha
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.