Masalah klik Custom ListView pada item di Android

110

Jadi saya memiliki objek ListView kustom. Item daftar memiliki dua tampilan teks yang ditumpuk di atas satu sama lain, ditambah bilah kemajuan horizontal yang ingin saya sembunyikan sampai saya benar-benar melakukan sesuatu. Di ujung kanan adalah kotak centang yang hanya ingin saya tampilkan saat pengguna perlu mendownload update ke database mereka. Ketika saya menonaktifkan kotak centang dengan mengatur visibilitas ke Visibilitas.GONE, saya bisa mengklik item daftar. Ketika kotak centang terlihat, saya tidak dapat mengklik apa pun di daftar kecuali kotak centang. Saya telah melakukan beberapa pencarian tetapi belum menemukan sesuatu yang relevan dengan situasi saya saat ini. Saya menemukan pertanyaan initapi saya menggunakan ArrayAdapter yang diganti karena saya menggunakan ArrayLists untuk memuat daftar database secara internal. Apakah saya hanya perlu mendapatkan tampilan LinearLayout dan menambahkan onClickListener seperti yang dilakukan Tom? Saya tidak yakin.

Berikut XML tata letak baris listview:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:padding="6dip">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="0dip"
        android:layout_weight="1"
        android:layout_height="fill_parent">
        <TextView
            android:id="@+id/UpdateNameText"
            android:layout_width="wrap_content"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:textSize="18sp"
            android:gravity="center_vertical"
            />
        <TextView
            android:layout_width="fill_parent"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:id="@+id/UpdateStatusText"
            android:singleLine="true"
            android:ellipsize="marquee"
            />
        <ProgressBar android:id="@+id/UpdateProgress" 
                     android:layout_width="fill_parent" 
                     android:layout_height="wrap_content"
                     android:indeterminateOnly="false" 
                     android:progressDrawable="@android:drawable/progress_horizontal" 
                     android:indeterminateDrawable="@android:drawable/progress_indeterminate_horizontal" 
                     android:minHeight="10dip" 
                     android:maxHeight="10dip"                    
                     />
    </LinearLayout>
    <CheckBox android:text="" 
              android:id="@+id/UpdateCheckBox" 
              android:layout_width="wrap_content" 
              android:layout_height="wrap_content" 
              />
</LinearLayout>

Dan inilah kelas yang memperluas ListActivity. Jelas itu masih dalam pengembangan jadi maafkan hal-hal yang hilang atau mungkin tertinggal:

public class UpdateActivity extends ListActivity {

    AccountManager lookupDb;
    boolean allSelected;
    UpdateListAdapter list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        lookupDb = new AccountManager(this);
        lookupDb.loadUpdates();

        setContentView(R.layout.update);
        allSelected = false;

        list = new UpdateListAdapter(this, R.layout.update_row, lookupDb.getUpdateItems());
        setListAdapter(list);

        Button btnEnterRegCode = (Button)findViewById(R.id.btnUpdateRegister);
        btnEnterRegCode.setVisibility(View.GONE);

        Button btnSelectAll = (Button)findViewById(R.id.btnSelectAll);
        btnSelectAll.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                allSelected = !allSelected;

                for(int i=0; i < lookupDb.getUpdateItems().size(); i++) {
                    lookupDb.getUpdateItem(i).setSelected(!lookupDb.getUpdateItem(i).isSelected());
                }

                list.notifyDataSetChanged();
                // loop through each UpdateItem and set the selected attribute to the inverse 

            } // end onClick
        }); // end setOnClickListener

        Button btnUpdate = (Button)findViewById(R.id.btnUpdate);
        btnUpdate.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
            } // end onClick
        }); // end setOnClickListener

        lookupDb.close();
    } // end onCreate


    @Override
    protected void onDestroy() {
        super.onDestroy();

        for (UpdateItem item : lookupDb.getUpdateItems()) {
            item.getDatabase().close();        
        }
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);

        UpdateItem item = lookupDb.getUpdateItem(position);

        if (item != null) {
            item.setSelected(!item.isSelected());
            list.notifyDataSetChanged();
        }
    }

    private class UpdateListAdapter extends ArrayAdapter<UpdateItem> {
        private List<UpdateItem> items;

        public UpdateListAdapter(Context context, int textViewResourceId, List<UpdateItem> items) {
            super(context, textViewResourceId, items);
            this.items = items;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View row = null;

            if (convertView == null) {
                LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                row = li.inflate(R.layout.update_row, null);
            } else {
                row = convertView;
            }

            UpdateItem item = items.get(position);

            if (item != null) {
                TextView upper = (TextView)row.findViewById(R.id.UpdateNameText);
                TextView lower = (TextView)row.findViewById(R.id.UpdateStatusText);
                CheckBox cb = (CheckBox)row.findViewById(R.id.UpdateCheckBox);

                upper.setText(item.getName());
                lower.setText(item.getStatusText());

                if (item.getStatusCode() == UpdateItem.UP_TO_DATE) {
                    cb.setVisibility(View.GONE);
                } else {
                    cb.setVisibility(View.VISIBLE);
                    cb.setChecked(item.isSelected());
                }

                ProgressBar pb = (ProgressBar)row.findViewById(R.id.UpdateProgress);
                pb.setVisibility(View.GONE);
            }
            return row;
        }

    } // end inner class UpdateListAdapter
}

edit: Saya masih mengalami masalah ini. Saya curang dan menambahkan handler onClick ke textviews tetapi tampaknya sangat bodoh karena fungsi onListItemClick () saya tidak dipanggil sama sekali ketika saya tidak mengklik kotak centang saya.

MattC
sumber

Jawaban:

243

Masalahnya adalah Android tidak mengizinkan Anda memilih item daftar yang memiliki elemen yang dapat difokuskan. Saya mengubah kotak centang pada item daftar agar memiliki atribut seperti ini:

android:focusable="false"

Sekarang item daftar saya yang berisi kotak centang (juga berfungsi untuk tombol) "dapat dipilih" dalam arti tradisional (menyala, Anda dapat mengklik di mana saja dalam item daftar dan penangan "onListItemClick" akan aktif, dll).

EDIT: Sebagai pembaruan, seorang pemberi komentar menyebutkan "Sekadar catatan, setelah mengubah visibilitas tombol, saya harus menonaktifkan fokus secara terprogram lagi."

MattC
sumber
24
Muncul solusi ini tidak bekerja saat ImageButton digunakan dalam item daftar. :(
Julian A.
1
Oke, tetapi bagaimana jika saya ingin kotak centang dan tampilan daftar saya klik saling eksklusif? Jika saya memilih Item ListView, saya tidak perlu mencentang kotaknya. Apakah ini mungkin dengan solusi ini?
Mike6679
@ Mike Ya, solusi ini masih memerlukan kotak centang untuk diklik secara eksplisit agar dapat berinteraksi dengannya. Itu hanya mengaktifkan kembali fungsionalitas dalam ListView yang secara misterius dilewati ketika Anda memiliki elemen yang dapat difokuskan dalam tata letak item daftar Anda.
MattC
2
Jawaban bagus terima kasih, bekerja dengan baik dengan ImageButtons juga. Sekadar catatan, setelah mengubah visibilitas tombol, saya harus menonaktifkan fokus secara terprogram lagi.
Ljdawson
1
Anda mungkin juga perlu menyetel android: clickable = "false"
Mina Samy
43

Jika Anda memiliki ImageButton di dalam item daftar, Anda harus menyetel descendantFocusabilitynilainya ke 'blocksDescendants' di elemen item daftar root.

android:descendantFocusability="blocksDescendants"

Dan focusableInTouchModebendera ke truedalam ImageButtontampilan.

android:focusableInTouchMode="true"
micnoy
sumber
1
Ini bekerja sempurna untuk listitem yang memiliki imagebuttons. Tapi ini mungkin berhasil kecuali ImageButton
raksja
12

Saya mengalami masalah serupa dan menemukan bahwa Kotak Centang agak rewel dalam ListView. Apa yang terjadi adalah ia memaksakan kehendaknya di seluruh ListItem, dan semacam menimpa onListItemClick. Anda mungkin ingin mengimplementasikan handler klik untuk itu, dan menyetel properti teks untuk Kotak Centang juga, daripada menggunakan TextView.

Saya akan mengatakan melihat ke dalam objek View ini juga, itu mungkin bekerja lebih baik daripada Kotak Centang

Tampilan Teks Dicentang

Andrew Burgess
sumber
6
Saya menemukan bahwa jika Anda menyetel setelan "dapat difokuskan" ke false untuk item yang dapat difokuskan dalam daftar, Anda dapat menggunakan fungsi onListItemClick lagi.
MattC
2
Namun kotak centang berubah menjadi oranye seperti item daftar. Ada yang tahu solusinya?
erdomester
8

gunakan baris ini di tampilan root item daftar

android: descendantFocusability = "blocksDescendants"

Suresh kumar
sumber