2011-01-15 17 views
111

Ho un ImageView che ha una risorsa immagine disegnabile impostata su un selettore. Come posso accedere a livello di programmazione al selettore e modificare le immagini dello stato evidenziato e non evidenziato?Sostituire le immagini del selettore a livello di programmazione

Ecco un codice di 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_hl e btn_icon con altre immagini.

+0

non sarebbe più semplice avere due selettori e scambiarli? – bigstones

+2

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

risposta

238

Per quanto ho potuto trovare (ho provato a fare qualcosa di simile anch'io), non c'è modo di modificare un singolo stato dopo che StateListDrawable è già stato definito. È possibile, tuttavia, definire uno nuovo tramite il 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 si può solo tenere due di loro a portata di mano, o crearne uno diverso come avete bisogno.

+1

Non ero in grado di aggiungere questo a una visualizzazione di immagine. setState non è disponibile su di esso. – dropsOfJupiter

+2

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

+2

Quindi ho un'altra nota correlata a questo. Speravo che tu possa rispondere. Ho questo selettore impostato su ImageView 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 sbagliando? C'è una sequenza? – dropsOfJupiter

6

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

Durante la costruzione di 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 del pulsante di navigazione ho qualcosa come il 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> 

Stavo per postare questo come una domanda e una risposta, ma visto che hai posto la stessa domanda, ecco qui. Nota, questo ti fa risparmiare un sacco di definizioni di file xml. sono andato giù da circa 50-100 definizioni xml fino a circa 4 !.

+0

Il codice navstelistdrawable rende il selettore xml ridondante. – Emile

+0

Ciao emilie, Esiste la possibilità che i drawable come sfondo di un pulsante non vengano visualizzati per la prima volta per nessun motivo. Attualmente sto riscontrando il problema in cui è necessario toccare l'area del pulsante per far apparire lo sfondo, oppure uscire 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 è stato testato per tutte le densità dello schermo? – ryvianstyron

+0

Salve, no, questo è stato scritto in modo corretto mentre era indietro ed era solo per un dispositivo al momento. Non sono sicuro di quale tipo di problema si possa arrisolare, anche se sono consapevole che densità e retini di schermi multipli non dovrebbero presentare un problema. – Emile

Problemi correlati