Фільтр подання списку Android


94

Я створив перегляд списку в android, і я хочу додати текст редагування над списком, і коли користувач введе текст, список буде відфільтровано відповідно до вводу користувача

хто-небудь може сказати мені, будь ласка, чи є спосіб фільтрувати адаптер списку в android?


1
Привіт, спробуй цей приклад Приклад перший і другий Приклад 2 Я реалізував те саме на основі цих підручників .. Сподіваюся, це допоможе тобі
Праньяні

5
Найкраща відповідь просто не надала мені достатньо інформації. Ця відповідь на подібне запитання має більше контексту і була точно достатньою інформацією, щоб я розібрався.
Джеймс Скемп

Я використовую подання утилізатора, я хочу фільтрувати записи, але я використовую користувацькі кнопки, щоб вводити текст редагування, як користувацьку клавіатуру, але я отримую затримку швидкого клацання кнопки, чи можете ви допомогти мені вийти з цього. У мене запис у тисячах
Sagar

Відповіді:


141

Додайте EditText поверх вашого списку у своєму файлі макета .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 до тексту редагування, а всередині методу зворотного виклику застосувати фільтр до адаптера вашого списку.

РЕДАГУВАТИ

Для того, щоб отримати фільтр до призначеного для користувача 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;
    }
}

Усередині perforFiltering () вам потрібно здійснити фактичне порівняння пошукового запиту зі значеннями у вашій базі даних. Він передасть свій результат методу objaviteResults () .


Я створив спеціальний адаптер, який розширює BaseAdapter, і всередині нього я визначив Вектор мого об'єкта, який буде показаний у списку, коли я намагаюся використовувати наведений вище код, я не міг знайти метод getFilter у своєму Адаптері, тому Ви могли б скажіть будь-ласка, чи потрібно мені реалізовувати якийсь інтерфейс ??
Amira Elsayed Ismail 02

Фільтрування даних у випадку BaseAdapter є дещо складним. Вам доведеться застосувати Filterable інтерфейс для вашої реалізації BaseAdapter. Тоді у вас буде метод getFilter (), і всередині нього ви повинні реалізувати два методи зворотного виклику для роботи; void objaviteResults () та FilterResults виконують фільтрування (обмеження CharSequence).
Пуруш Павар

Ви можете підтримати на простому прикладі, будь ласка?
Amira Elsayed Ismail 02

Так. Перевірте розділ EDIT моєї відповіді.
Пуруш Павар

1
Я пропоную вам опублікувати ще одне запитання щодо SO щодо цього. Тому що це не належний спосіб продовжувати задавати різні запитання в одному дописі. Що ж, як заголовок, просто скопіюйте весь арраліст спочатку в інший тимчасовий аррайлист, а всередині методу onPerformFiltering () використовуйте цей тимчасовий список для пошуку. Це вирішить вашу проблему. І, будь ласка, проголосуйте та / або прийміть відповідь, якщо це допомогло вам.
Пуруш Павар

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

Якщо хтось все ще зацікавлений у цій темі, я вважаю, що найкращим підходом для фільтрування списків є створення загального класу Filter та використання його з деякими базовими методами відображення / узагальнення, що містяться в пакеті Java SDK для старої школи. Ось що я зробив:

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" подання), передаючи посилання на ваш адаптер, ваш список і метод, який потрібно викликати для фільтрації:

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

Єдине, чого бракує зараз, - це перевизначити метод "getFilter" у класі адаптера:

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

Готово! Вам слід успішно відфільтрувати свій список - Звичайно, ви також повинні реалізувати алгоритм фільтрування найкращим чином, що описує ваші потреби, наведений нижче код - лише приклад. . Сподіваюся, це допомогло, подбайте.


Я не знаю про android, але пам’ятаю, як мені сказали намагатися уникати роздумів, якщо це можливо, в c #, оскільки він досить ресурсоємний (я зазвичай працюю на мобільних додатках Windows, тому це може бути проблемою), чи стосується це на android? чи рефлексія має такий самий ефект, як побудова фактичного класу без дженериків? Я думав створити шаблон для фільтрування і просто додати клас і метод, що використовуються як параметри
Cruces

Так, ти маєш рацію. Те саме стосується і тут, відображення надає ваги обробці програми, але в цьому випадку це дуже просте використання, і оскільки ми використовуємо її із загальним позначенням / шаблоном, це також допомагає компілятору. Удачі!
jbrios777

Примітка. Якщо ви використовуєте рефлексію, у вас можуть бути проблеми із затуманенням (дексгард / прогард).
Олексій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.