Filter Tampilan Daftar Android

94

Saya telah membuat tampilan daftar di android dan saya ingin menambahkan teks edit di atas daftar dan ketika pengguna memasukkan teks daftar akan disaring sesuai dengan input pengguna

Adakah yang bisa memberi tahu saya tolong jika ada cara untuk memfilter daftar adaptor di android?

Amira Elsayed Ismail
sumber
1
Hai coba contoh ini Contoh satu dan yang kedua Contoh 2 Saya telah menerapkan hal yang sama berdasarkan tutorial ini .. Saya harap ini akan membantu Anda
Pragnani
5
Jawaban teratas tidak memberikan informasi yang cukup bagi saya. Jawaban untuk pertanyaan serupa ini memiliki lebih banyak konteks, dan merupakan informasi yang cukup untuk membuat saya terselesaikan.
James Skemp
Saya menggunakan tampilan pendaur ulang Saya ingin memfilter catatan tetapi saya menggunakan tombol khusus untuk memberikan masukan ke teks edit seperti keypad khusus tetapi saya mendapatkan penundaan pada tombol klik cepat, bisakah Anda membantu saya keluar dari ini. Saya memiliki catatan dalam ribuan
Sagar

Jawaban:

141

Tambahkan EditText di atas tampilan daftar Anda dalam file tata letak .xml. Dan dalam aktivitas / fragmen Anda ..

lv = (ListView) findViewById(R.id.list_view);
    inputSearch = (EditText) findViewById(R.id.inputSearch);

// Adding items to listview
adapter = new ArrayAdapter<String>(this, R.layout.list_item, R.id.product_name,    products);
lv.setAdapter(adapter);       
inputSearch.addTextChangedListener(new TextWatcher() {

    @Override
    public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
        // When user changed the Text
        MainActivity.this.adapter.getFilter().filter(cs);
    }

    @Override
    public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) { }

    @Override
    public void afterTextChanged(Editable arg0) {}
});

Dasarnya di sini adalah menambahkan OnTextChangeListener ke teks edit Anda dan di dalam metode callbacknya menerapkan filter ke adaptor listview Anda.

EDIT

Untuk mendapatkan filter ke BaseAdapter khusus Anda, Anda harus menerapkan antarmuka yang Dapat Difilter .

class CustomAdapter extends BaseAdapter implements Filterable {

    public View getView(){
    ...
    }
    public Integer getCount()
    {
    ...
    }

    @Override
    public Filter getFilter() {

        Filter filter = new Filter() {

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {

                arrayListNames = (List<String>) results.values;
                notifyDataSetChanged();
            }

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {

                FilterResults results = new FilterResults();
                ArrayList<String> FilteredArrayNames = new ArrayList<String>();

                // perform your search here using the searchConstraint String.

                constraint = constraint.toString().toLowerCase();
                for (int i = 0; i < mDatabaseOfNames.size(); i++) {
                    String dataNames = mDatabaseOfNames.get(i);
                    if (dataNames.toLowerCase().startsWith(constraint.toString()))  {
                        FilteredArrayNames.add(dataNames);
                    }
                }

                results.count = FilteredArrayNames.size();
                results.values = FilteredArrayNames;
                Log.e("VALUES", results.values.toString());

                return results;
            }
        };

        return filter;
    }
}

Di dalam performFiltering (), Anda perlu melakukan perbandingan sebenarnya dari kueri penelusuran dengan nilai-nilai dalam database Anda. Ini akan meneruskan hasilnya ke metode publishResults () .

Purush Pawar
sumber
Saya telah membuat adaptor khusus yang memperluas BaseAdapter dan di dalamnya saya telah menentukan Vektor objek saya yang akan ditampilkan dalam daftar, ketika saya mencoba menggunakan kode di atas, saya tidak dapat menemukan metode getFilter di Adaptor saya, Anda juga bisa tolong beritahu saya jika saya harus menerapkan antarmuka apapun ??
Amira Elsayed Ismail
Memfilter data dalam kasus BaseAdapter agak rumit. Anda harus menerapkan antarmuka yang Dapat Difilter untuk penerapan BaseAdapter Anda. Anda kemudian akan memiliki metode getFilter () dan di dalamnya Anda harus mengimplementasikan dua metode callback untuk bekerja; void publishResults () dan FilterResults performFiltering (kendala CharSequence).
Purush Pawar
bisakah Anda mendukung dengan contoh sederhana?
Amira Elsayed Ismail
Iya. Periksa bagian EDIT jawaban saya.
Purush Pawar
1
Saya sarankan Anda untuk memposting pertanyaan lain tentang SO mengenai hal ini. Karena ini bukan cara yang tepat untuk terus mengajukan pertanyaan berbeda ke dalam postingan yang sama. Nah, sebagai permulaan, cukup salin seluruh daftar larik ke daftar larik sementara lainnya terlebih dahulu dan di dalam metode onPerformFiltering () gunakan daftar sementara ini untuk mencari. Ini akan menyelesaikan masalah Anda. Dan tolong beri suara positif dan / atau terima jawabannya jika itu membantu Anda.
Purush Pawar
9

Terapkan adaptor Anda yang Dapat Difilter:

public class vJournalAdapter extends ArrayAdapter<JournalModel> implements Filterable{
private ArrayList<JournalModel> items;
private Context mContext;
....

lalu buat kelas Filter Anda:

private class JournalFilter extends Filter{

    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        FilterResults result = new FilterResults();
        List<JournalModel> allJournals = getAllJournals();
        if(constraint == null || constraint.length() == 0){

            result.values = allJournals;
            result.count = allJournals.size();
        }else{
            ArrayList<JournalModel> filteredList = new ArrayList<JournalModel>();
            for(JournalModel j: allJournals){
                if(j.source.title.contains(constraint))
                    filteredList.add(j);
            }
            result.values = filteredList;
            result.count = filteredList.size();
        }

        return result;
    }
    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        if (results.count == 0) {
            notifyDataSetInvalidated();
        } else {
            items = (ArrayList<JournalModel>) results.values;
            notifyDataSetChanged();
        }
    }

}

Dengan cara ini, adaptor Anda dapat difilter, Anda dapat meneruskan item filter ke filter adaptor dan melakukan pekerjaannya. Saya berharap ini akan membantu.

M.Kouchi
sumber
1

Jika ada yang masih tertarik dengan subjek ini, saya menemukan bahwa pendekatan terbaik untuk memfilter daftar adalah dengan membuat kelas Filter generik dan menggunakannya dengan beberapa teknik refleksi / generik dasar yang terdapat dalam paket SDK jadul Java. Inilah yang saya lakukan:

public class GenericListFilter<T> extends Filter {

    /**
     * Copycat constructor
     * @param list  the original list to be used
     */
    public GenericListFilter (List<T> list, String reflectMethodName, ArrayAdapter<T> adapter) {
        super ();

        mInternalList = new ArrayList<>(list);
        mAdapterUsed  = adapter;

        try {
            ParameterizedType stringListType = (ParameterizedType)
                    getClass().getField("mInternalList").getGenericType();
            mCompairMethod =
                    stringListType.getActualTypeArguments()[0].getClass().getMethod(reflectMethodName);
        }
        catch (Exception ex) {
            Log.w("GenericListFilter", ex.getMessage(), ex);

            try {
                if (mInternalList.size() > 0) {
                    T type = mInternalList.get(0);
                    mCompairMethod = type.getClass().getMethod(reflectMethodName);
                }
            }
            catch (Exception e) {
                Log.e("GenericListFilter", e.getMessage(), e);
            }

        }
    }

    /**
     * Let's filter the data with the given constraint
     * @param constraint
     * @return
     */
    @Override protected FilterResults performFiltering(CharSequence constraint) {
        FilterResults results = new FilterResults();
        List<T> filteredContents = new ArrayList<>();

        if ( constraint.length() > 0 ) {
            try {
                for (T obj : mInternalList) {
                    String result = (String) mCompairMethod.invoke(obj);
                    if (result.toLowerCase().startsWith(constraint.toString().toLowerCase())) {
                        filteredContents.add(obj);
                    }
                }
            }
            catch (Exception ex) {
                Log.e("GenericListFilter", ex.getMessage(), ex);
            }
        }
        else {
            filteredContents.addAll(mInternalList);
        }

        results.values = filteredContents;
        results.count  = filteredContents.size();
        return results;
    }

    /**
     * Publish the filtering adapter list
     * @param constraint
     * @param results
     */
    @Override protected void publishResults(CharSequence constraint, FilterResults results) {
        mAdapterUsed.clear();
        mAdapterUsed.addAll((List<T>) results.values);

        if ( results.count == 0 ) {
            mAdapterUsed.notifyDataSetInvalidated();
        }
        else {
            mAdapterUsed.notifyDataSetChanged();
        }
    }

    // class properties
    private ArrayAdapter<T> mAdapterUsed;
    private List<T> mInternalList;
    private Method  mCompairMethod;
}

Dan setelah itu, satu-satunya hal yang perlu Anda lakukan adalah membuat filter sebagai kelas anggota (mungkin dalam "onCreate" Tampilan) dengan meneruskan referensi adaptor Anda, daftar Anda, dan metode yang akan dipanggil untuk pemfilteran:

this.mFilter = new GenericFilter<MyObjectBean> (list, "getName", adapter);

Satu-satunya hal yang hilang sekarang, adalah mengganti metode "getFilter" di kelas adaptor:

@Override public Filter getFilter () {
     return MyViewClass.this.mFilter;
}

Semua selesai! Anda harus berhasil memfilter daftar Anda - Tentu saja, Anda juga harus menerapkan algoritma filter Anda dengan cara terbaik yang menggambarkan kebutuhan Anda, kode di bawah ini hanyalah sebuah contoh. . Semoga membantu, hati-hati.

jbrios777
sumber
Saya tidak tahu tentang android, tetapi saya ingat saya diberitahu untuk mencoba menghindari refleksi jika memungkinkan di c # karena ini cukup intensif sumber daya (saya biasanya bekerja pada aplikasi windows mobile jadi ini bisa menjadi masalah), apakah ini berlaku di android? atau apakah refleksi memiliki efek yang sama seperti membangun kelas yang sebenarnya tanpa obat generik? Saya sedang berpikir untuk membuat template untuk dapat difilter dan hanya menambahkan kelas dan metode yang digunakan sebagai parameter
Cruces
Ya, Anda benar. Hal yang sama berlaku di sini, refleksi memberi bobot pada pemrosesan program, tetapi dalam kasus ini penggunaannya sangat sederhana, dan karena kita menggunakannya dengan notasi generik / template, ini juga membantu kompiler. Semoga berhasil!
jbrios777
NB Anda mungkin memiliki masalah dengan obfuscation (dexguard / proguard) jika Anda menggunakan refleksi.
Alexey