自定义 AutoCompleteTextView 行为

Posted

技术标签:

【中文标题】自定义 AutoCompleteTextView 行为【英文标题】:Custom AutoCompleteTextView behavior 【发布时间】:2012-02-20 09:46:54 【问题描述】:

开箱即用,AutoCompleteTextView 小部件似乎无法匹配列表值中间的输入字符串 - 匹配总是在开头进行;例如,输入“ar”匹配“argentina”,但不匹配“hungary”。

如何搜索单词中间的文字?谁能给我一个想法?

提前致谢!

【问题讨论】:

我在这里做类似的事情!!! ***.com/questions/12854336/… 【参考方案1】:

您需要编写一个自定义的Filter 类并自己实现performFiltering 方法。此方法采用CharSequence 参数,您可以使用该参数执行所需的任何字符串操作,以便从数据集中生成匹配列表(在您的情况下,您可以使用String.contains 而不是String.startsWith)。 performFiltering 函数不在 UI 线程上运行。

然后您将匹配列表作为FilterResults 对象返回,其中包含Object (您的匹配列表,可能是ArrayList)和int count 这是匹配列表的大小。

最后,实现 publishResults 回调方法,一旦工作线程生成匹配列表,该方法就会返回,允许您在 AutoCompleteTextView 的适配器上调用 notifyDataSetChanged 以便它可以显示结果。

【讨论】:

你能举个例子吗? 我知道距离这个答案已经有很长时间了,但它是我发现的关于这个主题的最准确的答案之一(顺便说一句,也是最难找到的答案之一)。谢谢! Victor 是对的,这是一种简单的方法:只需将 android.widget.ArrayAdapter 的全部内容复制粘贴到一个名为 CustomArrayAdapter 的新类中,然后更改位于 performFiltering 和 publishResults 中的 2 个“startsWith”事件通过“包含”。很简单。【参考方案2】:

老问题,但仍然相关。在其他几个问题的指导下,使用 filterable 实现了一个自定义适配器。我制作了一个简单的通用适配器,可以使用包含进行搜索。关于它的快速注释:

我使用的是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);
        
    

【讨论】:

这就是答案,我不得不改变一些东西,但效果很好。【参考方案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;

【讨论】:

【参考方案4】:

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

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

状态 特征 斥责 迟到

你的算法应该是这样的

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

【讨论】:

以上是关于自定义 AutoCompleteTextView 行为的主要内容,如果未能解决你的问题,请参考以下文章

AutoCompleteTextView 的自定义过滤器在单击时返回错误的字符串

将其值设置为“”后无法过滤 AutoCompleteTextView

Arraylist 中有 1000 个条目的 AutocompleteTextView 不起作用

Android自己主动提示文本框(AutoCompleteTextView)

AutoCompleteTextView(自动完成文本框)的基本使用

AutoCompleteTextView的使用