Apa perbedaan antara status yang dipilih, dicentang, dan diaktifkan di Android?

Jawaban:

182

Perbedaan Checked dan Activated sebenarnya cukup menarik. Bahkan dokumentasi Google meminta maaf (penekanan di bawah ditambahkan):

... Misalnya, dalam tampilan daftar dengan satu atau beberapa pilihan diaktifkan, tampilan dalam kumpulan pilihan saat ini diaktifkan. (Um, ya, kami sangat menyesal tentang terminologi di sini.) Status yang diaktifkan disebarkan ke turunan dari tampilan yang disetelnya.

Jadi inilah perbedaannya:

  1. Activated diperkenalkan di Honeycomb sehingga Anda tidak dapat menggunakannya sebelumnya
  2. Diaktifkan sekarang menjadi properti dari setiap Tampilan. Ini memiliki metode setActivated () dan isActivated ()
  3. Activated merambat ke turunan View yang disetel
  4. Diperiksa berkisar pada Tampilan yang menerapkan antarmuka yang Dapat Dicentang. Metode setChecked (), isChecked (), toggle ()
  5. ListView (setelah Honeycomb) memanggil setChecked () ATAU setActivated () bergantung pada versi Android seperti di bawah ini (diambil dari kode sumber 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));
        }
    }

    Perhatikan variabel mCheckStates. Ini melacak posisi mana dalam daftar Anda yang diperiksa / diaktifkan. Ini dapat diakses melalui, misalnya, getCheckedItemPositions (). Perhatikan juga bahwa panggilan ke ListView.setItemChecked () memanggil hal di atas. Dengan kata lain, itu bisa disebut setItemActivated ().

  6. Sebelum Honeycomb kami harus menerapkan solusi untuk mencerminkan state_checked di item daftar kami. Ini karena ListView memanggil setChecked () HANYA di Tampilan paling atas dalam tata letak (dan tata letak tidak menerapkan checkable) ... dan TIDAK menyebar tanpa bantuan. Solusi tersebut adalah dalam bentuk berikut: Perluas tata letak root untuk mengimplementasikan Checkable. Dalam konstruktornya, secara rekursif temukan semua turunan yang mengimplementasikan Checkable. Saat setChecked () dll ... dipanggil, teruskan panggilan ke Tampilan tersebut. Jika tampilan tersebut mengimplementasikan daftar negara yang dapat digambar (misalnya Kotak Centang) dengan drawable yang berbeda untuk state_checked, maka status yang dicentang akan tercermin di UI.

  7. Untuk membuat latar belakang yang bagus ke item daftar setelah Honeycomb, yang perlu Anda lakukan adalah memiliki daftar status yang dapat digambar dengan dapat digambar untuk state_activated seperti ini (dan tentu saja gunakan 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. Untuk melakukan latar belakang yang bagus ke item daftar sebelum HoneyComb Anda akan melakukan sesuatu seperti di atas untuk state_checked dan Anda JUGA perlu memperluas tampilan teratas Anda untuk mengimplementasikan antarmuka Checkable. Di dalamnya, Anda kemudian perlu memberi tahu Android apakah status yang Anda implementasikan benar atau salah dengan mengimplementasikan onCreateDrawableState () dan memanggil refreshDrawableState () setiap kali status berubah.

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

... dan kode untuk mengimplementasikan Checkable yang dikombinasikan dengan state_checked di RelativeLayout bisa jadi:

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

Berkat yang berikut:

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

Stackoverflow: Cara menambahkan status tombol kustom

Stackoverflow: Tampilan Custom Checkable yang merespons Selector

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
sumber
4
jawaban ini tak ternilai harganya. Saya berharap saya akan membacanya sebelum mencoba untuk mengetahui bagaimana menerapkan tata letak yang Dapat Dicentang, dll. Terima kasih banyak.
Blake Mumford
12
jawaban yang bagus, tetapi tidak membahas item yang "dipilih". Saya menemukan jawabannya dalam kalimat BENAR SEBELUM yang Anda kutip: 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.) sumber
woojoo666
warna latar belakang kustom saya hanya muncul di belakang item yang dipilih / terfokus, bukan item yang dicentang, saat menggunakan metode pasca-Honeycomb yang Anda posting di atas: memanggil setItemChecked()dan kemudian menggunakan selektor dengan propertiandroid:state_activated="true"
woojoo666
1
Terima kasih banyak, saya menyia-nyiakan 3 hari untuk mencoba mencari tahu sampai akhirnya saya memutuskan untuk bertanya pada diri sendiri "apa perbedaan antara diperiksa, dipilih dan diaktifkan", menyebalkan bahwa berurusan dengan sesuatu yang begitu sederhana seperti menu harus rumit, rekayasa berlebihan oleh para genius Google, hampir tampak seperti penghalang yang sengaja dibuat oleh perusahaan ini untuk memperlambat perusahaan lain.
Gubatron
20

Menurut dok :

  • android: state_selected Boolean . " true" jika item ini harus digunakan saat objek adalah pilihan pengguna saat ini saat menavigasi dengan kontrol arah (seperti saat menavigasi daftar dengan d-pad); " false" jika item ini harus digunakan saat objek tidak dipilih. Status yang dipilih digunakan saat fokus (android: state_focused) tidak memadai (seperti saat tampilan daftar memiliki fokus dan item di dalamnya dipilih dengan d-pad).

  • android: state_checked Boolean . " true" jika item ini harus digunakan saat objek dicentang; " false" jika harus digunakan saat objek tidak dicentang.

  • android: state_activated Boolean . " true" jika item ini harus digunakan saat objek diaktifkan sebagai pilihan tetap (seperti untuk "menyorot" item daftar yang dipilih sebelumnya dalam tampilan navigasi tetap); " false" jika harus digunakan saat objek tidak diaktifkan. Diperkenalkan di API level 11 .

Saya pikir dokumennya cukup jelas, jadi apa masalahnya?

AMerle
sumber
5
Bisakah Anda menjelaskan lebih lanjut tentang android: state_selected. Bagaimana keadaan ketika itu diatur ke benar?
Anderson
@Anderson itu akan bergantung pada ViewGroup yang Anda gunakan - ListView, RecyclerView (mungkin LayoutManagers-nya), GridView mungkin memiliki implementasi yang berbeda: ListView memanggil setFocused di mana GridView memanggil setSelected misalnya. Ini mungkin hanya kasus memeriksa aplikasi Anda pada versi platform yang berbeda.
ataulm
1
@Anderson: Jika Anda memiliki daftar, dan pengguna memiliki tombol panah, salah satunya "dipilih", dan saat mereka panah ke atas / bawah, pilihan berpindah ke atas / bawah. Ketika mereka menekan tombol "aktifkan", itu "mengaktifkan" kontrol, anggap saja pemilihannya mirip dengan gerakan mouse, dan centang / aktivasi sama samar-samar dengan mengklik.
Mooing Duck
Saya bertanya-tanya, saya akan menggunakan diaktifkan untuk menyorot satu item dalam tampilan daftar, tetapi apakah itu mengatur aktivasi untuk item daftar lainnya ke false ... jika tidak lakukan salah satu dari ini lakukan itu jadi saya tidak perlu menemukannya item anak lain yang diaktifkan dan setel aktivasi ke false?
Lion789
0

Berikut adalah solusi lain untuk masalah ini: https://github.com/jiahaoliuliu/CustomizedListRow/blob/master/src/com/jiahaoliuliu/android/customizedlistview/MainActivity.java

Saya telah mengganti metode setOnItemClickListener dan memeriksa kasus yang berbeda dalam kode. Tapi yang pasti solusi Marvin jauh lebih baik.

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
sumber