Qual è la differenza tra gli stati selezionati, controllati e attivati ​​in Android?


Risposte:


182

La differenza tra Checked e Activated è in realtà piuttosto interessante. Anche la documentazione di Google si scusa (enfasi sotto aggiunta):

... Ad esempio, in una visualizzazione elenco con selezione singola o multipla abilitata, vengono attivate le visualizzazioni nel gruppo di selezione corrente. (Ehm, sì, siamo profondamente dispiaciuti per la terminologia qui.) Lo stato attivato viene propagato ai figli della vista su cui è impostato.

Quindi ecco la differenza:

  1. Activated è stato introdotto in Honeycomb quindi non puoi usarlo prima
  2. Attivato è ora una proprietà di ogni vista. Ha i metodi setActivated () e isActivated ()
  3. Attivato si propaga ai figli della vista su cui è impostato
  4. Checked ruota attorno a una vista che implementa l'interfaccia Checkable. Metodi setChecked (), isChecked (), toggle ()
  5. ListView (dopo Honeycomb) chiama setChecked () OR setActivated () a seconda della versione di Android come di seguito (preso dal codice sorgente di Android):

    if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) {
        if (child instanceof Checkable) {
            ((Checkable) child).setChecked(mCheckStates.get(position));
        } else if (getContext().getApplicationInfo().targetSdkVersion
                >= android.os.Build.VERSION_CODES.HONEYCOMB) {
            child.setActivated(mCheckStates.get(position));
        }
    }
    

    Notare la variabile mCheckStates. Tiene traccia di quali posizioni nell'elenco sono controllate / attivate. Questi sono accessibili tramite, ad esempio, getCheckedItemPositions (). Notare anche che una chiamata a ListView.setItemChecked () richiama quanto sopra. In altre parole, potrebbe essere ugualmente chiamato setItemActivated ().

  6. Prima di Honeycomb dovevamo implementare soluzioni alternative per riflettere state_checked nelle voci dell'elenco. Questo perché ListView chiama setChecked () SOLO sulla vista più in alto nel layout (ei layout non implementano il checkable) ... e NON si propaga senza aiuto. Queste soluzioni alternative erano del seguente formato: Estendere il layout principale per implementare Checkable. Nel suo costruttore, trova ricorsivamente tutti i figli che implementano Checkable. Quando vengono chiamati setChecked () ecc ..., passare la chiamata a quelle viste. Se queste viste implementano i drawable dell'elenco di stato (ad esempio un CheckBox) con un drawable diverso per state_checked, lo stato selezionato si riflette nell'interfaccia utente.

  7. Per fare uno sfondo piacevole a una voce di elenco dopo Honeycomb, tutto ciò che devi fare è avere un elenco di stati disegnabile con un disegnabile per lo stato state_activated in questo modo (e usa setItemChecked () ovviamente):

    <item android:state_pressed="true"
        android:drawable="@drawable/list_item_bg_pressed"/>
    <item android:state_activated="true"
        android:drawable="@drawable/list_item_bg_activated"/>
    <item android:drawable="@drawable/list_item_bg_normal"/>
    

  8. Per fare uno sfondo piacevole a un elemento dell'elenco prima di HoneyComb, dovresti fare qualcosa di simile a quanto sopra per state_checked e devi INOLTRE estendere la tua vista superiore per implementare l'interfaccia Checkable. All'interno di ciò devi quindi dire ad Android se lo stato che stai implementando è vero o falso implementando onCreateDrawableState () e chiamando refreshDrawableState () ogni volta che lo stato cambia.

    <item android:state_pressed="true"
        android:drawable="@drawable/list_item_bg_pressed"/>
    <item android:state_checked="true"
        android:drawable="@drawable/list_item_bg_checked"/>
    <item android:drawable="@drawable/list_item_bg_normal"/>
    

... e il codice per implementare Checkable combinato con state_checked in un RelativeLayout potrebbe essere:

public class RelativeLayoutCheckable extends RelativeLayout implements Checkable {

    public RelativeLayoutCheckable(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public RelativeLayoutCheckable(Context context) {
        super(context);
    }

    private boolean mChecked = false;

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
    }
    @Override
    public boolean isChecked() {
        return mChecked;
    }

    @Override
    public void setChecked(boolean checked) {
        mChecked = checked;
        refreshDrawableState();
    }

    private static final int[] mCheckedStateSet = {
        android.R.attr.state_checked,
    };

    @Override
    protected int[] onCreateDrawableState(int extraSpace) {
        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
        if (isChecked()) {
            mergeDrawableStates(drawableState, mCheckedStateSet);
        }
        return drawableState;
    }    

    @Override
    public void toggle() {
        setChecked(!mChecked);
    }
}

Grazie a quanto segue:

http://sriramramani.wordpress.com/2012/11/17/custom-states/

Stackoverflow: come aggiungere uno stato del pulsante personalizzato

Stackoverflow: visualizzazione controllabile personalizzata che risponde al selettore

http://www.charlesharley.com/2012/programming/custom-drawable-states-in-android/

http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList

http://blog.marvinlabs.com/2010/10/29/custom-listview-ability-check-items/


4
questa risposta non ha prezzo. Vorrei averlo letto prima di provare a capire come implementare un layout verificabile, ecc. Grazie mille.
Blake Mumford

12
ottima risposta, ma non riguarda gli elementi "selezionati". Ho trovato la risposta nelle frasi PRIMA di quella che hai citato: Selection is a transient property, representing the view (hierarchy) the user is currently interacting with. Activation is a longer-term state that the user can move views in and out of. For example, in a list view with single or multiple selection enabled, the views in the current selection set are activated. (Um, yeah, we are deeply sorry about the terminology here.) fonte
woojoo666

il mio colore di sfondo personalizzato viene visualizzato solo dietro gli elementi selezionati / focalizzati, non selezionati, quando si utilizza il metodo post-Honeycomb che hai pubblicato sopra: chiamando setItemChecked()e quindi utilizzando un selettore con proprietàandroid:state_activated="true"
woojoo666

1
Grazie mille, ho sprecato 3 giorni cercando di capirlo finché alla fine ho deciso di chiedermi "qual è la differenza tra controllato, selezionato e attivato", fa schifo che affrontare qualcosa di così semplice come un menu deve essere così complicato, overengineering dai geni di Google, sembra quasi un ostacolo apposta da questa azienda per rallentare gli altri.
Gubatron

20

Secondo il doc :

  • android: state_selected Boolean . " true" se questo elemento deve essere utilizzato quando l'oggetto è la selezione corrente dell'utente durante la navigazione con un controllo direzionale (come quando si naviga in un elenco con un tasto direzionale); " false" se questo elemento deve essere utilizzato quando l'oggetto non è selezionato. Lo stato selezionato viene utilizzato quando lo stato attivo (android: state_focused) non è sufficiente (ad esempio quando la visualizzazione elenco ha lo stato attivo e un elemento al suo interno viene selezionato con una croce direzionale).

  • android: state_checked Boolean . " true" se questo elemento deve essere utilizzato quando l'oggetto viene controllato; " false" se deve essere utilizzato quando l'oggetto è deselezionato.

  • android: state_activated Boolean . " true" se questo elemento deve essere utilizzato quando l'oggetto è attivato come selezione persistente (come per "evidenziare" l'elemento dell'elenco precedentemente selezionato in una vista di navigazione persistente); " false" se deve essere utilizzato quando l'oggetto non è attivato. Introdotto nel livello API 11 .

Penso che il documento sia abbastanza chiaro, quindi qual è il problema?


5
Puoi approfondire su Android: state_selected. Quali sono le circostanze in cui è impostato su vero?
Anderson

@ Anderson dipenderà dal ViewGroup che stai utilizzando: ListView, RecyclerView (probabilmente i suoi LayoutManagers), GridView potrebbe avere implementazioni diverse: ListView chiama setFocused dove GridView chiama setSelected per esempio. Potrebbe essere solo un caso di controllare la tua app su diverse versioni della piattaforma.
ataulm

1
@ Anderson: se si dispone di un elenco e l'utente ha i tasti freccia, uno è "selezionato" e quando si freccia su / giù, la selezione si sposta su / giù. Quando premono il tasto "attiva", "attiva" il controllo, pensa che la selezione sia vagamente simile al passaggio del mouse e il controllo / attivazione come vagamente simile al clic.
Mooing Duck

Mi stavo chiedendo, userò attivato per evidenziare un elemento in una visualizzazione elenco, ma imposta l'attivazione per altri elementi dell'elenco su falso ... in caso contrario, fallo in modo da non doverlo trovare l'altro elemento figlio attivato e impostare l'attivazione su false?
Lion789

0

Ecco un'altra soluzione per questo problema: https://github.com/jiahaoliuliu/CustomizedListRow/blob/master/src/com/jiahaoliuliu/android/customizedlistview/MainActivity.java

Ho sovrascritto il metodo setOnItemClickListener e controllato diversi casi nel codice. Ma in definitiva la soluzione di Marvin è decisamente migliore.

listView.setOnItemClickListener(new OnItemClickListener() {

@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position,
        long id) {
    CheckedTextView checkedTextView =
            (CheckedTextView)view.findViewById(R.id.checkedTextView);
    // Save the actual selected row data
    boolean checked = checkedTextView.isChecked();
    int choiceMode = listView.getChoiceMode();
    switch (choiceMode) {
    // Not choosing anything
    case (ListView.CHOICE_MODE_NONE):
        // Clear all selected data
        clearSelection();
        //printCheckedElements();
        break;
    // Single choice
    case (ListView.CHOICE_MODE_SINGLE):
        // Clear all the selected data
        // Revert the actual row data
        clearSelection();
        toggle(checked, checkedTextView, position);
        //printCheckedElements();
        break;
    // Multiple choice
    case (ListView.CHOICE_MODE_MULTIPLE):
    case (ListView.CHOICE_MODE_MULTIPLE_MODAL):
        // Revert the actual selected row data
        toggle(checked, checkedTextView, position);
        //printCheckedElements();
        break;
    }
    }
});
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.