Bagaimana cara memperbarui ListView di Android secara dinamis [ditutup]

159

Di Android, bagaimana saya bisa ListViewmemfilter berdasarkan input pengguna, di mana item yang ditampilkan diperbarui secara dinamis berdasarkan TextViewnilai?

Saya mencari sesuatu seperti ini:

-------------------------
| Text View             |
-------------------------
| List item             |
| List item             |
| List item             |
| List item             |
|                       |
|                       |
|                       |
|                       |
-------------------------
Hamy
sumber
7
Saya mencalonkan untuk membuka kembali. Saya telah memperbarui teks untuk menjadikan ini lebih dari sebuah pertanyaan, dan ini jelas merupakan sumber daya komunitas yang berharga karena jawaban masih masuk
Hamy
Silakan buka kembali pertanyaannya. Ini jelas membantu.
SilentNot

Jawaban:

286

Pertama, Anda perlu membuat tata letak XML yang memiliki EditText, dan 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>

Ini akan meletakkan semuanya dengan benar, dengan EditText yang bagus di atas ListView. Selanjutnya, buat ListActivity seperti biasa, tetapi tambahkan setContentView()panggilan dalam onCreate()metode ini sehingga kami menggunakan tata letak yang baru saja dinyatakan. Ingatlah bahwa kami telah mengidentifikasi ListViewsecara khusus, dengan android:id="@android:id/list". Ini memungkinkan ListActivityuntuk mengetahui mana yang ListViewingin kita gunakan dalam tata letak yang kita nyatakan.

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

Menjalankan aplikasi sekarang harus menunjukkan yang sebelumnya ListView, dengan kotak yang bagus di atas. Untuk membuat kotak itu melakukan sesuatu, kita perlu mengambil input darinya, dan membuat input itu menyaring daftar. Sementara banyak orang telah mencoba melakukan ini secara manual, sebagian besar ListView Adapter kelas datang dengan Filterobjek yang dapat digunakan untuk melakukan penyaringan secara otomatis. Kami hanya perlu menyalurkan input dari EditTextke Filter. Ternyata itu cukup mudah. Untuk menjalankan tes cepat, tambahkan baris ini ke onCreate()panggilan Anda

adapter.getFilter().filter(s);

Perhatikan bahwa Anda perlu menyimpan ListAdaptervariabel Anda untuk membuat ini berfungsi - saya telah menyimpan ArrayAdapter<String>dari saya sebelumnya ke variabel yang disebut 'adaptor'.

Langkah selanjutnya adalah mendapatkan input dari EditText. Ini sebenarnya butuh sedikit pemikiran. Anda dapat menambahkan OnKeyListener()ke EditText. Namun, pendengar ini hanya menerima beberapa peristiwa penting . Misalnya, jika pengguna memasukkan 'wyw', teks prediksi kemungkinan akan merekomendasikan 'mata'. Sampai pengguna memilih 'wyw' atau 'eye', Anda OnKeyListenertidak akan menerima acara utama. Beberapa mungkin lebih suka solusi ini, tetapi saya merasa frustasi. Saya ingin setiap acara utama, jadi saya punya pilihan untuk memfilter atau tidak. Solusinya adalah a TextWatcher. Cukup buat dan tambahkan TextWatcherke EditText, dan teruskan ListAdapter Filterpermintaan filter setiap kali teks berubah. Ingatlah untuk menghapus TextWatcherin OnDestroy()! Inilah solusi terakhir:

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);
}
Hamy
sumber
7
Apakah ada cara mudah untuk memfilter ListView dalam mode "berisi" alih-alih "dimulai dengan" seperti yang dilakukan solusi ini?
Viktor Brešan
12
Viktor - Jika kata-kata yang Anda minati dipisahkan oleh spasi, maka itu akan melakukan ini secara otomatis. Kalau tidak, tidak juga. Mungkin cara termudah adalah dengan mensubklasifikasikan Adaptor dengan memperluasnya, dan mengganti metode getFilter untuk mengembalikan objek Filter yang Anda tetapkan. Lihat github.com/android/platform_frameworks_base/blob/master/core/… untuk memahami cara kerja default ArrayFilter - akan mudah untuk menyalin 95% dari kode ini dan mengubah baris 479 dan 486
Hamy
2
Hamy, langganan yang bagus! Saya punya pertanyaan: Saya telah menerapkan ini dan setelah setiap huruf yang saya ketik, ListView menghilang selama beberapa detik dan kemudian kembali, difilter. Sudahkah Anda mengalami ini? Intuisi saya adalah karena saya memiliki lebih dari 600 item dalam daftar, dengan fungsi toString () yang tidak sepele.
Lowellk
2
Dalam mode lansekap pada layar yang lebih kecil, keyboard EditText + mengambil seluruh layar dan ListView tidak terlihat! Ada solusi?
Martin Konicek
4
Apakah ini benar-benar perlu? > Ingatlah untuk menghapus TextWatcher di OnDestroy ()
Jojo
10

menjalankan program akan menyebabkan kekuatan ditutup.

Saya menukar saluran:

android: id = "@ + building_list / search_box"

dengan

android: id = "@ + id / search_box"

mungkinkah itu masalahnya? Untuk apa '@ + building_list'?

j7nn7k
sumber
Johe, ketika Anda mengatakan R.id.something, sesuatu ada di id karena Anda mengatakan android: id = "@ + id / search_box". Jika Anda mengatakan android: id = "@ + building_list / search_box" maka dalam kode Anda dapat memanggil findViewById (R.building_list.search_box); Apa pengecualian tingkat atas yang Anda dapatkan? Kode ini disalin tanpa kompilasi tes, jadi saya mungkin meninggalkan setidaknya satu kesalahan di suatu tempat
Hamy
Hai Hamy, Anda mereferensikan "@ + building_list / search_box" dalam kode dengan "filterText = (EditText) findViewById (R.id.search_box);" Itu sebabnya saya bertanya-tanya.
j7nn7k
1
Forceclose occorrs ketika mulai mengetik. Bagian dari kesalahan: ERROR / AndroidRuntime (188): java.lang.NullPointerException 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): at xxx.com.ListFilter $ 1. onTextChanged (ListFilter.java:46) 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): di android.widget.TextView.sendOnTextChanged (TextView.java:6102) 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): at android.widget.TextView.handleTextChanged (TextView.java:6143) 02-11 07: 30: 29.828: ERROR / AndroidRuntime (188): di android.widget.TextView $ ChangeWatcher.onTextChanged (TextView.java) : 6286)
j7nn7k
Johe, Ups - sepertinya saya mencoba memodifikasi kode untuk menyingkirkan @ + building_list (karena itu adalah titik kebingungan) tetapi saya tidak menangkapnya di mana-mana. Terima kasih atas tipnya! Hanya mengubahnya ke @ + id harus memperbaikinya
Hamy
4

saya punya masalah dengan pemfilteran, bahwa hasilnya telah disaring, tetapi tidak dikembalikan !

jadi sebelum pemfilteran (aktivitas dimulai) saya membuat daftar cadangan .. (hanya daftar lain, berisi data yang sama)

pada pemfilteran, filter dan listadapter terhubung ke daftar utama.

tetapi filter itu sendiri menggunakan data dari daftar cadangan.

ini memastikan dalam kasus saya, bahwa daftar tersebut segera diperbarui dan bahkan pada penghapusan istilah-pencarian-karakter, daftar akan berhasil dipulihkan dalam setiap kasus :)

terima kasih atas solusi ini.

cV2
sumber