Jaka jest różnica między stanami wybranymi, sprawdzonymi i aktywowanymi w systemie Android?

Odpowiedzi:

182

Różnica między Checked i Activated jest w rzeczywistości dość interesująca. Nawet dokumentacja Google jest przepraszająca (podkreślenie poniżej dodane):

... Na przykład w widoku listy z włączonym pojedynczym lub wielokrotnym wyborem widoki w bieżącym zbiorze wskazań są aktywowane. (Hm, tak, bardzo nam przykro z powodu tej terminologii.) Stan aktywacji jest propagowany do dzieci widoku, na którym jest ustawiony.

Oto różnica:

  1. Activated został wprowadzony w Honeycomb, więc nie możesz go wcześniej używać
  2. Aktywowany jest teraz właściwością każdego widoku. Ma metody setActivated () i isActivated ()
  3. Activated propaguje się do elementów podrzędnych Widoku, na którym jest ustawiony
  4. Zaznaczone obraca się wokół widoku implementującego interfejs Checkable. Metody setChecked (), isChecked (), toggle ()
  5. ListView (po Honeycomb) wywołuje setChecked () LUB setActivated () w zależności od wersji Androida, jak poniżej (pobrane z kodu źródłowego Androida):

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

    Zwróć uwagę na zmienną mCheckStates. Śledzi, które pozycje na Twojej liście są zaznaczone / aktywowane. Są one dostępne na przykład poprzez getCheckedItemPositions (). Należy również zauważyć, że wywołanie ListView.setItemChecked () wywołuje powyższe. Innymi słowy, można go również nazwać setItemActivated ().

  6. Przed wprowadzeniem Honeycomb musieliśmy wdrożyć obejścia, aby odzwierciedlić state_checked na naszej liście. Dzieje się tak, ponieważ ListView wywołuje setChecked () TYLKO na najwyższym widoku w układzie (a układy nie implementują możliwości sprawdzania) ... i NIE propaguje się bez pomocy. Te obejścia miały następującą postać: Rozszerz układ główny, aby zaimplementować opcję Checkable. W swoim konstruktorze, rekurencyjnie znajdź wszystkie elementy potomne, które implementują Checkable. Gdy wywoływana jest metoda setChecked () etc ..., przekaż wywołanie do tych widoków. Jeśli te widoki implementują elementy rysunkowe z listy stanów (np. CheckBox) z innym drawable dla state_checked, wówczas stan zaznaczenia jest odzwierciedlany w interfejsie użytkownika.

  7. Aby stworzyć ładne tło dla elementu listy po Honeycomb, wszystko, co musisz zrobić, to mieć listę stanów z możliwością rysowania dla stanu state_activated w ten sposób (i oczywiście użyj setItemChecked ()):

    <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. Aby zrobić ładne tło dla elementu listy przed HoneyComb, zrobiłbyś coś takiego jak powyżej dla state_checked i musisz RÓWNIEŻ rozszerzyć swój najwyższy widok, aby zaimplementować interfejs Checkable. W ramach tego musisz następnie powiedzieć systemowi Android, czy implementowany stan jest prawdziwy, czy fałszywy, implementując onCreateDrawableState () i wywołując refreshDrawableState () za każdym razem, gdy stan się zmienia.

    <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"/>

... a kod do implementacji Checkable w połączeniu z state_checked w RelativeLayout mógłby wyglądać następująco:

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

Podziękowania dla:

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

Stackoverflow: jak dodać stan przycisku niestandardowego

Stackoverflow : niestandardowy widok z możliwością zaznaczania, który reaguje na selektor

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/

Martin Harvey
źródło
4
ta odpowiedź jest bezcenna. Żałuję, że nie przeczytałem go, zanim spróbowałem wdrożyć układ, który można sprawdzić, itp. Dziękuję bardzo.
Blake Mumford,
12
świetna odpowiedź, ale nie dotyczy „wybranych” elementów. Znalazłem odpowiedź w zdaniach 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.)
tuż
mój niestandardowy kolor tła pojawia się tylko za wybranymi / zaznaczonymi elementami, a nie zaznaczonymi, podczas korzystania z metody plastra miodu, którą opublikowałeś powyżej: wywołanie, setItemChecked()a następnie użycie selektora z właściwościąandroid:state_activated="true"
woojoo666
1
Dziękuję bardzo, zmarnowałem 3 dni próbując to rozgryźć, aż w końcu zdecydowałem się zadać sobie pytanie „jaka jest różnica między zaznaczonym, wybranym i aktywowanym”, jest do bani, że radzenie sobie z czymś tak prostym jak menu musi być tak skomplikowane, przepracowane przez geniuszy Google, prawie wydaje się przeszkodą, którą ta firma celowo stawia, aby spowolnić innych.
Gubatron
20

Według doc :

  • android: state_selected Boolean . " true" jeśli ta pozycja ma być używana, gdy obiekt jest aktualnie wybranym przez użytkownika podczas nawigacji za pomocą kontrolki kierunkowej (na przykład podczas nawigacji po liście za pomocą pada kierunkowego); „ false”, jeśli ten element ma być używany, gdy obiekt nie jest wybrany. Wybrany stan jest używany, gdy fokus (android: state_focused) nie jest wystarczający (na przykład gdy widok listy ma fokus, a element w nim jest zaznaczony za pomocą pada kierunkowego).

  • android: state_checked Boolean . " true" jeśli ta pozycja ma być używana, gdy obiekt jest zaznaczony; „ false” jeśli ma być używane, gdy obiekt jest odznaczony.

  • android: state_activated Boolean . " true" jeśli ta pozycja ma być używana, gdy obiekt jest aktywowany jako trwały wybór (np. w celu "podświetlenia" poprzednio wybranej pozycji listy w stałym widoku nawigacji); " false" jeśli ma być używany, gdy obiekt nie jest aktywowany. Wprowadzono na poziomie API 11 .

Myślę, że dokument jest całkiem jasny, więc w czym problem?

AMerle
źródło
5
Czy możesz rozwinąć temat android: state_selected. W jakich okolicznościach jest to prawda?
Anderson
@Anderson będzie to zależeć od używanej ViewGroup - ListView, RecyclerView (prawdopodobnie jego LayoutManagers), GridView może mieć różne implementacje: ListView wywołuje setFocused, gdzie GridView wywołuje setSelected na przykład. Może to być tylko przypadek sprawdzenia aplikacji na różnych platformach.
ataulm
1
@Anderson: Jeśli masz listę, a użytkownik ma klawisze strzałek, jeden jest „wybrany”, a kiedy strzałka w górę / w dół, przesuwa się w górę / w dół. Kiedy naciskają klawisz „aktywuj”, „aktywuje” kontrolkę, myśląc, że jej wybór jest nieco podobny do najechania myszą, a zaznaczenie / aktywacja jest niejako podobne do kliknięcia.
Mooing Duck,
Zastanawiałem się, mam zamiar używać aktywacji do podświetlania jednej pozycji w widoku listy, ale czy ustawia aktywację innych pozycji listy na fałsz ... jeśli nie, zrób to, więc nie muszę znajdować inny aktywowany element podrzędny i ustawić aktywację na fałsz?
Lion789
0

Oto inne rozwiązanie tego problemu: https://github.com/jiahaoliuliu/CustomizedListRow/blob/master/src/com/jiahaoliuliu/android/customizedlistview/MainActivity.java

Zastąpiłem metodę setOnItemClickListener i sprawdziłem różne przypadki w kodzie. Ale ostatecznie rozwiązanie Marvina jest znacznie lepsze.

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;
    }
    }
});
jiahao
źródło