Cách tự động cập nhật ListView trên Android [đã đóng]


159

Trên Android, làm cách nào tôi có thể ListViewlọc các bộ lọc dựa trên đầu vào của người dùng, nơi các mục được hiển thị được cập nhật động dựa trên TextViewgiá trị?

Tôi đang tìm kiếm một cái gì đó như thế này:

-------------------------
| Text View             |
-------------------------
| List item             |
| List item             |
| List item             |
| List item             |
|                       |
|                       |
|                       |
|                       |
-------------------------

7
Tôi đề cử mở lại. Tôi đã cập nhật văn bản để đưa ra nhiều câu hỏi hơn và đây rõ ràng là một tài nguyên cộng đồng có giá trị vì câu trả lời vẫn đang đến
Hamy

Vui lòng mở lại câu hỏi. Nó rõ ràng là hữu ích.
SilentNot

Câu trả lời:


286

Trước tiên, bạn cần tạo một bố cục XML có cả EditText và ListView.

<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <!-- Pretty hint text, and maxLines -->
    <EditText android:id="@+building_list/search_box" 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:hint="type to filter"
        android:inputType="text"
        android:maxLines="1"/>

    <!-- Set height to 0, and let the weight param expand it -->
    <!-- Note the use of the default ID! This lets us use a 
         ListActivity still! -->
    <ListView android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1" 
         /> 

</LinearLayout>

Điều này sẽ đặt mọi thứ ra một cách chính xác, với một EditText đẹp phía trên ListView. Tiếp theo, tạo ListActivity như bình thường, nhưng thêm một setContentView()cuộc gọi trong onCreate()phương thức để chúng tôi sử dụng bố cục được khai báo gần đây của chúng tôi. Hãy nhớ rằng chúng tôi đã ID ListViewđặc biệt, với android:id="@android:id/list". Điều này cho phép ListActivitybiết cái mà ListViewchúng ta muốn sử dụng trong bố cục khai báo của chúng ta.

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

        setContentView(R.layout.filterable_listview);

        setListAdapter(new ArrayAdapter<String>(this,
                       android.R.layout.simple_list_item_1, 
                       getStringArrayList());
    }

Chạy ứng dụng bây giờ sẽ hiển thị trước đó của bạn ListView, với một hộp đẹp ở trên. Để làm cho hộp đó làm một cái gì đó, chúng ta cần lấy đầu vào từ nó và làm cho bộ lọc đầu vào đó lọc danh sách. Trong khi nhiều người đã cố gắng thực hiện việc này một cách thủ công, hầu hết ListView Adapter các lớp đều đi kèm với một Filterđối tượng có thể được sử dụng để thực hiện quá trình lọc tự động. Chúng ta chỉ cần ống đầu vào từ EditTextvào Filter. Hóa ra là khá dễ dàng. Để chạy thử nghiệm nhanh, hãy thêm dòng này vào onCreate()cuộc gọi của bạn

adapter.getFilter().filter(s);

Lưu ý rằng bạn sẽ cần lưu của bạn ListAdaptervào một biến để thực hiện công việc này - Tôi đã lưu ArrayAdapter<String>từ trước đó vào một biến có tên là 'bộ chuyển đổi'.

Bước tiếp theo là lấy đầu vào từ EditText. Điều này thực sự cần một chút suy nghĩ. Bạn có thể thêm một OnKeyListener()vào EditText. Tuy nhiên, người nghe này chỉ nhận được một số sự kiện quan trọng . Ví dụ: nếu người dùng nhập 'wyw', văn bản dự đoán có thể sẽ đề xuất 'mắt'. Cho đến khi người dùng chọn 'wyw' hoặc 'eye', bạn OnKeyListenersẽ không nhận được một sự kiện quan trọng. Một số có thể thích giải pháp này, nhưng tôi thấy nó bực bội. Tôi muốn mọi sự kiện quan trọng, vì vậy tôi có quyền lựa chọn lọc hoặc không lọc. Giải pháp là a TextWatcher. Chỉ cần tạo và thêm a TextWatchervào EditTextvà chuyển ListAdapter Filteryêu cầu bộ lọc mỗi khi văn bản thay đổi. Hãy nhớ để loại bỏ TextWatchertrong OnDestroy()! Đây là giải pháp cuối cùng:

private EditText filterText = null;
ArrayAdapter<String> adapter = null;

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

    setContentView(R.layout.filterable_listview);

    filterText = (EditText) findViewById(R.id.search_box);
    filterText.addTextChangedListener(filterTextWatcher);

    setListAdapter(new ArrayAdapter<String>(this,
                   android.R.layout.simple_list_item_1, 
                   getStringArrayList());
}

private TextWatcher filterTextWatcher = new TextWatcher() {

    public void afterTextChanged(Editable s) {
    }

    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
    }

    public void onTextChanged(CharSequence s, int start, int before,
            int count) {
        adapter.getFilter().filter(s);
    }

};

@Override
protected void onDestroy() {
    super.onDestroy();
    filterText.removeTextChangedListener(filterTextWatcher);
}

7
Có cách nào đơn giản để lọc ListView trong "chứa" thay vì "bắt đầu bằng" thời trang như giải pháp này không?
Viktor Brešan

12
Viktor - Nếu các từ bạn quan tâm được phân tách bằng dấu cách, thì nó sẽ tự động làm điều này. Nếu không, không thực sự. Có lẽ cách dễ nhất là phân lớp Adaptor bằng cách mở rộng nó và ghi đè phương thức getFilter để trả về một đối tượng Filter mà bạn xác định. Xem github.com/android/pl platform_frameworks_base/blob/master/core/, để hiểu cách thức ArrayFilter mặc định hoạt động - thật đơn giản để sao chép 95% mã này và thay đổi dòng 479 và 486
Hamy

2
Hamy, viết tuyệt vời! Mặc dù vậy, tôi có một câu hỏi: Tôi đã thực hiện điều này và sau mỗi chữ cái tôi gõ, ListView sẽ biến mất trong vài giây và sau đó quay lại, được lọc. Bạn đã có kinh nghiệm này? Trực giác của tôi là bởi vì tôi có hơn 600 mặt hàng trong danh sách, với các hàm toString () không tầm thường.
lowellk

2
Ở chế độ ngang trên màn hình nhỏ hơn, bàn phím EditText + sẽ hiển thị toàn bộ màn hình và ListView không hiển thị! Bất kì giải pháp nào?
Martin Konicek

4
Điều này có thực sự cần thiết? > Nhớ xóa TextWatcher trong OnDestroy ()
Jojo

10

chạy chương trình sẽ gây ra một lực lượng gần.

Tôi đổi dòng:

android: id = "@ + Building_list / search_box"

với

android: id = "@ + id / search_box"

Có thể đó là vấn đề? '@ + Building_list' để làm gì?


Johe, khi bạn nói R.id.s Something, một cái gì đó tồn tại trong id vì bạn đã nói android: id = "@ + id / search_box". Nếu bạn nói android: id = "@ + Building_list / search_box" thì trong mã bạn có thể gọi findViewById (R.building_list.search_box); Ngoại lệ cấp cao nhất bạn đang nhận được là gì? Mã này được sao chép khi biên dịch thử nghiệm, do đó tôi có thể để lại ít nhất một lỗi trong đó ở đâu đó
Hamy

Xin chào Hamy, bạn đã tham chiếu "@ + Building_list / search_box" trong mã với "filterText = (EditText) findViewById (R.id.search_box);" Đó là lý do tại sao tôi đã tự hỏi.
j7nn7k

1
Các lỗi đã xảy ra khi bắt đầu nhập. Một phần lỗi: ERROR / AndroidR.78 (188): java.lang.NullPulumException 02-11 07: 30: 29.828: ERROR / AndroidR.78 (188): tại xxx.com.ListFilter $ 1. onTextChanged (ListFilter.java:46) 02-11 07: 30: 29.828: ERROR / AndroidR.78 (188): tại android.widget.TextView.sendOnTextChanged (TextView.java:6102) 02-11 07: 30: 29.828: ERROR AndroidR.78 (188): tại android.widget.TextView.handleTextChanged (TextView.java:6143) 02-11 07: 30: 29.828: ERROR / AndroidR.78 (188): tại android.widget.TextView $ ChangeWatcher.onTextChanged (TextView.j : 6286)
j7nn7k

Johe, Rất tiếc - có vẻ như tôi đã cố gắng sửa đổi mã để thoát khỏi @ + Building_list (vì đó là một điểm gây nhầm lẫn) nhưng tôi đã không bắt được nó ở mọi nơi. Cảm ơn vì tiền hỗ trợ! Chỉ cần thay đổi nó thành @ + id nên sửa nó
Hamy

4

tôi gặp vấn đề với việc lọc, kết quả đó đã được lọc, nhưng không được khôi phục !

vì vậy trước khi lọc (bắt đầu hoạt động) tôi đã tạo một bản sao lưu danh sách .. (chỉ một danh sách khác, chứa cùng một dữ liệu)

khi lọc, bộ lọc và listad CHƯƠNG được kết nối với danh sách chính.

nhưng chính bộ lọc đã sử dụng dữ liệu từ danh sách được sao lưu.

điều này đảm bảo trong trường hợp của tôi, rằng danh sách đã được cập nhật ngay lập tức và ngay cả khi xóa các ký tự thuật ngữ tìm kiếm, danh sách được khôi phục thành công trong mọi trường hợp :)

cảm ơn vì giải pháp này

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.