มุมมองรายการกรอง Android


94

ฉันได้สร้างมุมมองรายการใน Android และฉันต้องการเพิ่มแก้ไขข้อความเหนือรายการและเมื่อผู้ใช้ป้อนข้อความรายการจะถูกกรองตามการป้อนข้อมูลของผู้ใช้

ใครช่วยบอกฉันทีว่ามีวิธีกรองรายการอะแดปเตอร์ใน Android ได้ไหม


1
สวัสดีลองดูตัวอย่างนี้ตัวอย่างที่หนึ่งและตัวอย่างที่สองตัวอย่างที่ 2ฉันได้ใช้สิ่งเดียวกันนี้ตามบทช่วยสอนนี้ฉันหวังว่านี่จะช่วยคุณได้
Pragnani

5
คำตอบยอดนิยมไม่ได้ให้ข้อมูลเพียงพอสำหรับฉัน คำตอบสำหรับคำถามที่คล้ายกันนี้มีบริบทมากกว่าและมีข้อมูลเพียงพอที่จะทำให้ฉันแยกแยะได้
James Skemp

ฉันใช้มุมมองรีไซเคิลฉันต้องการกรองบันทึก แต่ฉันใช้ปุ่มที่กำหนดเองเพื่อป้อนข้อมูลให้กับข้อความแก้ไขเช่นแป้นพิมพ์ที่กำหนดเอง แต่ฉันได้รับความล่าช้าในการคลิกปุ่มอย่างรวดเร็วคุณสามารถช่วยฉันออกจากสิ่งนี้ได้ฉันมีบันทึกเป็นพัน
Sagar

คำตอบ:


141

เพิ่ม EditText ที่ด้านบนของ listview ของคุณในไฟล์เลย์เอาต์. xml และในกิจกรรม / ส่วนของคุณ ..

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) {}
});

ขั้นพื้นฐานในที่นี้คือการเพิ่มOnTextChangeListenerลงในข้อความแก้ไขของคุณและภายในวิธีการโทรกลับจะใช้ตัวกรองกับอะแดปเตอร์ของ listview ของคุณ

แก้ไข

ในการรับตัวกรองไปยัง BaseAdapter ที่กำหนดเองของคุณคุณจะต้องใช้อินเทอร์เฟซที่กรองได้

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;
    }
}

ภายในperformFiltering ()คุณต้องทำการเปรียบเทียบจริงของคำค้นหากับค่าในฐานข้อมูลของคุณ มันจะส่งผลลัพธ์ไปยัง วิธีการPublishResults ()


ฉันได้สร้างอะแดปเตอร์แบบกำหนดเองที่ขยาย BaseAdapter และภายในนั้นฉันได้กำหนด Vector ของวัตถุของฉันที่จะแสดงในรายการเมื่อฉันพยายามใช้รหัสด้านบนฉันไม่พบเมธอด getFilter ในอะแดปเตอร์ของฉันคุณสามารถทำได้ กรุณาบอกฉันว่าฉันต้องใช้อินเทอร์เฟซใด ๆ ??
Amira Elsayed Ismail

การกรองข้อมูลในกรณีของ BaseAdapter นั้นค่อนข้างยุ่งยาก คุณจะต้องใช้อินเทอร์เฟซที่กรองได้กับการใช้งาน BaseAdapter ของคุณ คุณจะมีเมธอด getFilter () และภายในนั้นคุณจะต้องใช้วิธีการโทรกลับสองวิธีเพื่อทำงาน เป็นโมฆะ PublishResults () และ FilterResults performFiltering (CharSequence constraint)
Purush Pawar

ช่วยสนับสนุนด้วยตัวอย่างง่ายๆได้ไหม
Amira Elsayed Ismail

ใช่. ตรวจสอบส่วนแก้ไขของคำตอบของฉัน
Purush Pawar

1
ฉันขอแนะนำให้คุณโพสต์คำถามอื่นใน SO เกี่ยวกับเรื่องนี้ เนื่องจากไม่ใช่วิธีที่เหมาะสมในการถามคำถามต่างๆในโพสต์เดียวกัน ในทางที่ดีเพียงแค่คัดลอกรายการอาร์เรย์ทั้งหมดไปยังรายการอาร์เรย์ชั่วคราวอื่นก่อนและภายในเมธอด onPerformFiltering () ใช้รายการชั่วคราวนี้สำหรับการค้นหา วิธีนี้จะช่วยแก้ปัญหาของคุณ และโปรดโหวตและ / หรือยอมรับคำตอบหากช่วยคุณได้
Purush Pawar

9

ใช้อะแดปเตอร์ที่กรองได้:

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

จากนั้นสร้างคลาสตัวกรองของคุณ:

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

}

ด้วยวิธีนี้อะแดปเตอร์ของคุณสามารถกรองได้คุณสามารถส่งผ่านรายการตัวกรองไปยังตัวกรองของอะแด็ปเตอร์และทำงานได้ ฉันหวังว่านี่จะเป็นประโยชน์


1

ในกรณีที่ใครยังสนใจเรื่องนี้ฉันพบว่าแนวทางที่ดีที่สุดสำหรับการกรองรายการคือการสร้างคลาสตัวกรองทั่วไปและใช้กับเทคนิคการสะท้อนแสง / ทั่วไปพื้นฐานที่มีอยู่ในแพ็คเกจ SDK ของโรงเรียนเก่า Java นี่คือสิ่งที่ฉันทำ:

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;
}

และหลังจากนั้นสิ่งเดียวที่คุณต้องทำคือสร้างตัวกรองเป็นคลาสสมาชิก (อาจอยู่ใน "onCreate" ของ View) ผ่านการอ้างอิงอะแด็ปเตอร์รายการของคุณและวิธีที่จะเรียกใช้สำหรับการกรอง:

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

สิ่งเดียวที่ขาดหายไปตอนนี้คือการแทนที่เมธอด "getFilter" ในคลาสอะแด็ปเตอร์:

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

เสร็จหมดแล้ว! คุณควรกรองรายการของคุณได้สำเร็จ - แน่นอนว่าคุณควรใช้อัลกอริทึมการกรองของคุณด้วยวิธีที่ดีที่สุดที่อธิบายถึงความต้องการของคุณโค้ดต่อไปนี้เป็นเพียงตัวอย่างเท่านั้น . หวังว่ามันจะช่วยดูแล


ฉันไม่รู้เกี่ยวกับ Android แต่ฉันจำได้ว่าถูกบอกให้พยายามหลีกเลี่ยงการไตร่ตรองหากเป็นไปได้ใน c # เพราะมันค่อนข้างใช้ทรัพยากรมาก (ฉันมักจะทำงานกับแอพพลิเคชั่นมือถือ windows ดังนั้นอาจเป็นปัญหาได้) สิ่งนี้ใช้ได้กับ Android หรือไม่ หรือการสะท้อนกลับมีผลเช่นเดียวกับการสร้างชั้นเรียนจริงโดยไม่มีชื่อสามัญหรือไม่? ฉันกำลังคิดจะสร้างเทมเพลตสำหรับกรองและเพิ่มคลาสและวิธีการที่ใช้เป็นพารามิเตอร์
Cruces

ใช่คุณถูกต้อง เช่นเดียวกันกับที่นี่การสะท้อนให้น้ำหนักกับการประมวลผลโปรแกรม แต่ในกรณีนี้เป็นการใช้งานที่ง่ายมากและเนื่องจากเราใช้มันกับสัญกรณ์ทั่วไป / เทมเพลตจึงช่วยคอมไพเลอร์ได้ด้วย โชคดี!
jbrios777

หมายเหตุคุณอาจมีปัญหากับการทำให้สับสน (dexguard / proguard) หากคุณใช้การสะท้อนแสง
Alexey
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.