android ListView SearchView基本用法3

Android AUmaWSsSoi 2个月前 (05-07) 61次浏览 0个评论
文章目录[隐藏]

背景:

前面两篇文章,android RecyclerView SearchView基本用法1,android RecyclerView SearchView基本用法2 演示了RecyclerView如何跟SearchView配合使用,本篇主要讲ListView,在很多老的项目里面,列表相关的控件,基本上还是ListView,虽说目前已经是2019年了,ListView被使用的越来越少了。在搜索页面中,ListView跟RecyclerView处理有些不同,过滤逻辑这块有些差异。看Android官方文档推荐用Filter类处理过滤,然后在Filter类里面写具体的过滤规则。

解决办法:

使用ListView,需要为ListView设置对应的Adapter。

class Adapter extends BaseAdapter implements Filterable {

    private List<String> datas = new ArrayList<>();
    private List<String> filterDatas = new ArrayList<>();
    private boolean isInSearch = false;

    public void setInSearch(boolean inSearch) {
        this.isInSearch = inSearch;
    }

    public void setDatas(List<String> datas) {
        this.datas = datas;
    }

    @Override
    public int getCount() {
        if (isInSearch) {
            return filterDatas.size();
        } else {
            return datas.size();
        }
    }

    @Override
    public String getItem(int position) {
        if (isInSearch) {
            return filterDatas.get(position);
        } else {
            return datas.get(position);
        }
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        if (convertView == null) {
            convertView = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
            viewHolder = new ViewHolder(convertView);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        viewHolder.textView.setText(getItem(position));
        return convertView;
    }

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults();
                if (TextUtils.isEmpty(constraint)) {
                    results.count = datas.size();
                    results.values = datas;
                } else {
                    List<String> filterList = new ArrayList<>();
                    for (String content : datas) {
                        if (content.contains(constraint)) {
                            filterList.add(content);
                        }
                    }
                    results.count = filterList.size();
                    results.values = filterList;
                }
                return results;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                filterDatas = (List<String>) results.values;
                notifyDataSetChanged();
            }
        };
    }
}

class ViewHolder {
    TextView textView;

    public ViewHolder(@NonNull View itemView) {
        textView = itemView.findViewById(android.R.id.text1);
    }
}

Adapter的方法就是常用的模板方法,上面多了实现Filterable接口的代码。

我们为getFilter()方法返回了一个匿名的对象,这个匿名对象的两个方法我们都进行了重写实现,按照我们约定的逻辑。performFiltering()方法是过滤逻辑,实现自己的过滤规则,这段代码写的简单,是判断是否包含输入的字符,如果匹配,就添加到list中,这块可以结合自己业务需要,实现自己的逻辑。publishResults()方法是将过滤的数据传递给Adapter的数据源,然后刷新页面。

然后看看在SearchView中是如何用的,跟RecyclerView有啥区别。

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    @Override
    public boolean onQueryTextSubmit(String query) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        if (TextUtils.isEmpty(newText)) {
            adapter.setInSearch(false);
            adapter.setDatas(datas);
            adapter.notifyDataSetChanged();
        } else {
            adapter.setInSearch(true);
            adapter.getFilter().filter(newText);
        }
        return false;
    }
});

不同之处在于,ListView用的是Adapter.getFilter().filter(newText)方法,而RecycleView没这么复杂,就是一个普通的比较算法逻辑。没有调用系统特定的Api。

分析下Filter类的filter()执行过程,为何ListView会选择这样的方式。

系统Filter类的源码里面,public final void filter(CharSequence constraint, FilterListener listener)方法内部开启了一个子线程,然后呢,用子线程执行过滤的逻辑,就算是大量的数据,过于复杂的过滤规则也不会导致主线程阻塞。过滤完后,会通过Handler机制,触发主线程里面的publishResults(args.constraint, args.results)。

但是对于RecyclerView为啥不这样处理,暂未深入研究,有时间在分析。

参考资料:

https://stackoverflow.com/questions/14663725/list-view-filter-android

下载地址:

链接:https://pan.baidu.com/s/1MeAjMGQ6r0bnFX86QTmYgw 密码:3of4


java问与答 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:http://javaexception.com/archives/86
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址