Vấn đề nhấp vào ListView tùy chỉnh trên các mục trong Android


110

Vì vậy, tôi có một đối tượng ListView tùy chỉnh. Các mục danh sách có hai chế độ xem văn bản xếp chồng lên nhau, cộng với một thanh tiến trình ngang mà tôi muốn ẩn cho đến khi tôi thực sự làm điều gì đó. Ở ngoài cùng bên phải là hộp kiểm mà tôi chỉ muốn hiển thị khi người dùng cần tải xuống các bản cập nhật cho (các) cơ sở dữ liệu của họ. Khi tôi tắt hộp kiểm bằng cách đặt chế độ hiển thị thành Visibility.GONE, tôi có thể nhấp vào các mục trong danh sách. Khi hộp kiểm hiển thị, tôi không thể nhấp vào bất kỳ thứ gì trong danh sách ngoại trừ các hộp kiểm. Tôi đã thực hiện một số tìm kiếm nhưng không tìm thấy bất kỳ điều gì liên quan đến tình hình hiện tại của tôi. Tôi đã tìm thấy câu hỏi nàynhưng tôi đang sử dụng ArrayAdapter bị ghi đè vì tôi đang sử dụng ArrayLists để chứa danh sách cơ sở dữ liệu bên trong. Tôi có chỉ cần lấy chế độ xem LinearLayout và thêm onClickListener như Tom đã làm không? Tôi không chắc.

Đây là XML bố cục hàng 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>

Và đây là lớp mở rộng ListActivity. Rõ ràng là nó vẫn đang trong quá trình phát triển nên hãy tha thứ cho những thứ còn thiếu hoặc có thể còn sót lại:

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
}

chỉnh sửa: Tôi vẫn gặp sự cố này. Tôi đang gian lận và thêm trình xử lý onClick vào các chế độ xem văn bản nhưng có vẻ vô cùng ngu ngốc khi hàm onListItemClick () của tôi hoàn toàn không được gọi khi tôi không nhấp vào hộp kiểm của mình.

Câu trả lời:


243

Vấn đề là Android không cho phép bạn chọn các mục danh sách có các phần tử có thể lấy tiêu điểm trên đó. Tôi đã sửa đổi hộp kiểm trên mục danh sách để có một thuộc tính như sau:

android:focusable="false"

Giờ đây, các mục danh sách của tôi có chứa hộp kiểm (cũng hoạt động cho các nút) là "có thể chọn" theo nghĩa truyền thống (chúng sáng lên, bạn có thể nhấp vào bất kỳ đâu trong mục danh sách và trình xử lý "onListItemClick" sẽ kích hoạt, v.v.).

CHỈNH SỬA: Như một bản cập nhật, một người bình luận đã đề cập "Chỉ cần lưu ý, sau khi thay đổi khả năng hiển thị của nút, tôi phải tắt tiêu điểm theo chương trình một lần nữa."


24
Có vẻ như giải pháp này không hoạt động khi ImageButton được sử dụng trong mục danh sách. :(
Julian A.

1
Được nhưng nếu tôi muốn hộp kiểm và lần nhấp vào chế độ xem danh sách của mình loại trừ lẫn nhau thì sao? Nếu tôi chọn Mục ListView, tôi không nhất thiết phải chọn checkBox. Điều này có thể với giải pháp này?
Mike6679

@Mike Có, giải pháp này vẫn yêu cầu hộp kiểm phải được nhấp rõ ràng để được tương tác với. Nó chỉ bật lại chức năng trong ListView bị bỏ qua một cách bí ẩn khi bạn có các phần tử có thể lấy tiêu điểm trong bố cục mục danh sách của mình.
MattC

2
Cảm ơn câu trả lời tuyệt vời, hoạt động tốt với ImageButtons. Chỉ cần lưu ý, sau khi thay đổi khả năng hiển thị của nút, tôi phải tắt tiêu điểm theo chương trình một lần nữa.
Ljdawson

1
bạn cũng có thể cần thiết lập android: clickable = "false"
Mina Samy

43

Trong trường hợp bạn có ImageButton bên trong mục danh sách, bạn nên đặt descendantFocusabilitygiá trị thành 'blocksDescendants' trong phần tử mục danh sách gốc.

android:descendantFocusability="blocksDescendants"

focusableInTouchModelá cờ truetrong ImageButtonchế độ xem.

android:focusableInTouchMode="true"

1
Điều này hoạt động hoàn hảo cho listitem có nút hình ảnh. Nhưng công việc sức mạnh này trừ ImageButton
raksja

12

Tôi đã gặp sự cố tương tự xảy ra và thấy rằng CheckBox khá phức tạp trong ListView. Điều gì sẽ xảy ra là nó áp đặt ý chí của nó trên toàn bộ ListItem và loại ghi đè onListItemClick. Bạn có thể muốn triển khai một trình xử lý nhấp chuột cho điều đó và cũng đặt thuộc tính văn bản cho CheckBox, thay vì sử dụng TextViews.

Tôi muốn nói rằng hãy xem xét đối tượng View này, nó có thể hoạt động tốt hơn CheckBox

Chế độ xem văn bản được kiểm tra


6
Tôi nhận thấy rằng nếu bạn đặt cài đặt "có thể lấy tiêu điểm" thành false cho các mục có thể tiêu điểm trong danh sách, bạn có thể sử dụng lại chức năng onListItemClick của mình.
MattC

2
Tuy nhiên hộp kiểm chuyển sang màu cam giống như mục danh sách. Bất cứ ai biết một giải pháp?
erdomester

8

sử dụng dòng này trong chế độ xem gốc của mục danh sách

android :cendantFocusability = "blocksDescendants"

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.