自定义AutoCompleteTextView行为

9

默认情况下,AutoCompleteTextView小部件似乎无法匹配列表值中间的输入字符串-匹配总是在开头进行;例如,输入“ar”可以匹配“argentina”,但不能匹配“hungary”。

我该如何搜索单词中间的文本?有人能给我一个想法吗?

提前致谢!


我正在这里做类似的事情!!! https://dev59.com/Y-o6XIcBkEYKwwoYPR_f - Etienne Lawlor
4个回答

10
您需要编写一个自定义的 Filter 类,并自己实现 performFiltering 方法。该方法接受一个 CharSequence 参数,您可以使用它来执行任何字符串操作,以便从数据集中生成匹配项列表(在您的情况下,您可以使用 String.contains 而不是 String.startsWith)。performFiltering 函数不在 UI 线程上运行。
然后,您将匹配项列表作为 FilterResults 对象返回,其中包含一个 Object values(您的匹配项列表,可能是一个 ArrayList)和一个 int count,这是您的匹配项列表的大小。
最后,实现publishResults回调方法,该方法在工作线程生成匹配列表后返回,允许您在AutoCompleteTextView的适配器上调用notifyDataSetChanged以便它可以显示结果。

你能给我一个例子吗? - Chrishan
我知道这个答案已经过去很长时间了,但它是我在这个主题上找到的最准确的答案之一(顺便说一句,也是最难找到的)。谢谢! - nKn
2
Victor 是正确的,这里有一个简单的方法:只需将 android.widget.ArrayAdapter 的整个内容复制粘贴到一个名为 CustomArrayAdapter 的新类中,并在 performFiltering 和 publishResults 中的 2 个 "startsWith" 出现的位置更改为 "contains"。 简单易行。 - Damien Praca

6

这是一个旧问题,但仍然相关。根据其他一些问题的指导,使用filterable实现了自定义适配器。我做了一个简单的通用适配器,使用contains进行搜索。以下是一些注意事项:

我正在使用butterknife,但使用findviewbyid也很容易实现viewHolder。

布局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);
        }
    }
}

这就是答案,我不得不改一些东西,但现在完美运行。 - sdelvalle57

3
public class AutoCompleteAdapter <T> extends ArrayAdapter<T> implements Filterable {
    private List <T> listObjects;
    List<T> suggestions = new ArrayList<>();
    private Context context;
    public AutoCompleteAdapter(Context context, List<T> listObjects) {
        super(context, R.layout.list_item_simple, listObjects);
        this.listObjects = new ArrayList<>(listObjects);
        this.context = context;
    }
    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 constraint, 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();
        }
    }
};
@Override
public Filter getFilter() {
    return mFilter;
}
private static class ViewHolder {
    TextView title;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
    Object listObject = getItem(position);
    final ViewHolder viewHolder; // view lookup cache stored in tag
    if (convertView == null) {
        viewHolder = new ViewHolder();
        LayoutInflater inflater = LayoutInflater.from(getContext());
        convertView = inflater.inflate(R.layout.list_item_simple, parent, false);
        viewHolder.title = (TextView) convertView.findViewById(R.id.title);
        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }
    viewHolder.title.setText(listObject.toString());
    return convertView;
}

}


0

我的建议是将字符串解析为字符数组。 然后遍历每个字符,直到找到该字符串。

例如,假设您的搜索想要返回所有带有“ate”的单词,而单词列表是...

state trait berate late

您的算法应该像这样

将字符串解析成字符数组 循环遍历数组并寻找第一个“正确字符”(在我们的例子中为'a') 一旦找到该字符,请检查下一个字符,继续检查每个字符是否匹配,直到完全搜索到值。如果字符不匹配,则退出数组迭代并转到下一个单词。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接