Пользовательское поведение AutoCompleteTextView

По умолчанию виджет AutoCompleteTextView, похоже, не может сопоставить входную строку в середине значения списка — совпадения всегда выполняются в начале; например, ввод "ar" соответствует "argentina", но не "hungary".

Как я могу найти текст в середине слова? Кто-нибудь может дать мне идею?

Заранее спасибо !


person Chrishan    schedule 27.01.2012    source источник
comment
Я делаю что-то подобное ЗДЕСЬ !!! stackoverflow.com/questions/12854336/   -  person toobsco42    schedule 30.10.2012


Ответы (3)


Вам потребуется написать собственный класс Filter и реализовать performFiltering самостоятельно. Этот метод принимает аргумент CharSequence, который вы можете использовать для выполнения любых операций со строками, которые вам нужны для создания списка совпадений из вашего набора данных (в вашем случае вы можете использовать String.contains вместо String.startsWith). Функция performFiltering не запускается в потоке пользовательского интерфейса.

Затем вы возвращаете список совпадений в виде объекта FilterResults, который содержит Object значений (ваш список совпадений, вероятно, ArrayList) и int число, которое является размером вашего списка совпадений.

Наконец, реализуйте publishResults, который возвращается после того, как рабочий поток сгенерировал список совпадений, позволяя вам вызывать notifyDataSetChanged в вашем адаптере AutoCompleteTextView, чтобы он мог отображать результаты.

person Victor    schedule 27.01.2012
comment
не могли бы вы привести пример? - person Chrishan; 30.01.2012
comment
Я знаю, что с момента этого ответа прошло много времени, но это один из самых точных, которые я нашел по этому вопросу (и один из самых трудных для поиска, кстати). Спасибо! - person nKn; 11.01.2014
comment
Виктор прав, вот простой способ: просто скопируйте и вставьте все содержимое android.widget.ArrayAdapter в новый класс с именем CustomArrayAdapter и измените 2 вхождения startWith, расположенные в PerformFiltering и publishResults, на contains. Простой. - person Damien Praca; 06.01.2015

Старый вопрос, но все еще актуальный. Следуя указаниям нескольких других вопросов, реализован собственный адаптер с использованием filterable. Я сделал простой универсальный адаптер, который выполняет поиск с помощью содержимого. Быстрые заметки об этом:

Я использую Butterknife, но легко сделать viewHolder с помощью findviewbyid.

Макет R.layout.list_item_simple — это простой макет с текстовым представлением R.id.text_view_simple.

Объекту нужна toString, которая будет сравниваться.

public class SimpleContainsAutocompleteAdapter <T> extends ArrayAdapter<T> implements Filterable {
    private List <T> listObjects;
    List<T> suggestions = new ArrayList<>();
    private int resource;

    private Filter mFilter = new Filter(){
        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults filterResults = new FilterResults();

            if(constraint != null) {
                suggestions.clear();
                for(T object : listObjects){
                    if(object.toString().toLowerCase().contains(constraint.toString().toLowerCase())){
                        suggestions.add(object);
                    }
                }

                filterResults.values = suggestions;
                filterResults.count = suggestions.size();
            }

            return filterResults;
        }

        @Override
        protected void publishResults(CharSequence contraint, FilterResults results) {
            if(results == null){
                return;
            }

            List<T> filteredList = (List<T>) results.values;
            if(results.count > 0) {
                clear();
                for (T filteredObject : filteredList) {
                    add(filteredObject);
                }
                notifyDataSetChanged();
            }
        }
    };

    public SimpleContainsAutocompleteAdapter(Context context, List<T> listObjects) {
        super(context, R.layout.list_item_simple, listObjects);
        this.listObjects = new ArrayList<>(listObjects);
        this.resource = R.layout.list_item_simple;
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Object listObject = getItem(position);
        viewHolder holder;
        if(convertView != null) {
            holder = (viewHolder) convertView.getTag();
        }else{
            convertView = LayoutInflater.from(getContext()).inflate(resource, parent, false);
            holder = new viewHolder(convertView);
            convertView.setTag(holder);
        }

        holder.name.setText(listObject.toString());

        return convertView;
    }


    static class viewHolder {
        @InjectView(R.id.text_view_simple) TextView name;

        public viewHolder(View view) {
            ButterKnife.inject(this, view);
        }
    }
}
person Ryan C    schedule 08.05.2015
comment
Это ответ, мне пришлось что-то изменить, но работает отлично. - person sdelvalle57; 25.08.2015

Мой совет состоял бы в том, чтобы разобрать строку в массив символов. Затем повторяйте каждый символ, пока строка не будет найдена.

Например, предположим, что ваш поиск хотел вернуть все слова со словом «съел» в них, а список слов был...

государственная черта ругать поздно

Ваш алгоритм должен выглядеть примерно так

Возьмите строку и проанализируйте ее в массив символов Пройдитесь по массиву и найдите первый «правильный символ» (в нашем примере это «a»). Как только этот символ будет найден, проверьте следующий символ, продолжайте проверять каждый символ на соответствие до тех пор, пока искомое значение завершено. Если символ не совпадает, выходим из итерации массива и переходим к следующему слову.

person Michael Gonzalez    schedule 02.07.2012