EditText+ListView实时刷新ListView

写给自己和各位读者:

       首先说本人目前还是个菜鸟,每当遇到问题时,第一时间想到的是在网上查找大神的解决方案,其实在借鉴他人的方法时,也是在不断地提升自己,不管是代码的阅读能力,还是接收新知识,还是仅仅为以后的项目开发留下一个印象,都起到了很好的帮助。总之,多上网查找资料,多看一些好的解决方法,当你在实际开发中遇到这些问题时你就可以信手拈来。下面是我最近碰到的,通过在文本框中输入内容,如何实时刷新ListView的问题。

下面是效果图:

搜索前:

搜索后:

根据使用的ListView适配器的不同,有两种不同的实现方法。

第一种,如果你的ListView使用的是系统的ArrayAdapter,那么这个事情就变得很简单,只需要几行代码就可以解决:

       //给编辑框添加监听事件
        etSearch.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                //文本改变时,给adapter设置过滤器就行了,只需要一行代码
                listViewAdapter.getFilter().filter(charSequence);

            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });

 

 

第二种:由于大多数Adapter都是自定义的,所以不能直接调用上面这个方法,但是我们可以模仿ArrayAdapter来实现这个功能。那就是实现Filterable接口,通过实现Filterrable接口,我们就可以像上面那样调用getFilter()和filter()方法了。

首先要有一个实体类,用来模拟数据。

public class AppInfoBitmap {
    private String mName;
    private Bitmap mBitmap;

    //无参构造
    public AppInfoBitmap() {
    }

    //带参构造
    public AppInfoBitmap(String mName, Bitmap mBitmap) {
        this.mName = mName;
        this.mBitmap = mBitmap;
    }

    public String getmName() {
        return mName;
    }

    public void setmName(String mName) {
        this.mName = mName;
    }

    public Bitmap getmBitmap() {
        return mBitmap;
    }

    public void setmBitmap(Bitmap mBitmap) {
        this.mBitmap = mBitmap;
    }
}

 

接下来自定义一个Adapter(ListViewAdapter)继承自BaseAdapter,实现了Filterable接口。

实现Filterable,必须要实现两个方法。

分别是:

protected FilterResults performFiltering(CharSequence charSequence);
protected void publishResults(CharSequence charSequence, FilterResults filterResults);

其次我们向外提供了一个getFilter()方法,用来生成Filter对象,进而调用Filter类中的filter()方法,最终实现过滤功能。

public Filter getFilter() {
        if (mFilter==null){
            mFilter=new ArrayFilter();
        }
        return mFilter;
    }

 

下面就是比较完整的代码了(此处没有包含Adapter一些常用处理,用最简洁的代码来说明问题):

public class AppListViewAdapter extends BaseAdapter implements Filterable{

    private Context mContext;

    //Adapter数据源
    private List<AppInfoBitmap> mAppInfoList;

    //过滤相关
    /*
    * 过滤器上的锁可以同步复制原始数据
    * */
    private final Object mLock=new Object();

    //对象数组的备份,当调用ArrayFilter的时候初始化和使用。此时,对象数组只包含已经过滤的数据。
    private ArrayList<AppInfoBitmap> mOriginalValues;
    private ArrayFilter mFilter;




    @Override
    public Filter getFilter() {
        if (mFilter==null){
            mFilter=new ArrayFilter();
        }
        return mFilter;
    }



    //写一个ArrayFilter类继承Filter
    public class ArrayFilter extends Filter{

        //执行过滤的方法
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) {
            /*
            * 一个带有首字母约束的数组过滤器,每一项
            * 不是以该首字母开头的都会被移除该list
            * */
            //过滤的结果
            FilterResults results=new FilterResults();

            //原始数据为空时,上锁,同步复制原始数据
            if (mOriginalValues==null){
                synchronized (mLock){
                    mOriginalValues=new ArrayList<>(mAppInfoList);
                }
            }

            //当首字母为空时
            if (charSequence==null||charSequence.length()==0){
                ArrayList<AppInfoBitmap> list;
                synchronized (mLock){
                    //同步复制一个原始备份数据
                    list=new ArrayList<>(mOriginalValues);
                }

                //此时返回的results就是原始的数据,不必进行过滤
                results.values=list;
                results.count=list.size();
            }else {
                //转化为小写
                String prefixString=charSequence.toString().toLowerCase() ;

                ArrayList<AppInfoBitmap> values;
                //同步复制一个原始备份数据
                synchronized (mLock){
                    values=new ArrayList<>(mOriginalValues);
                }

                final int count=values.size();
                final ArrayList<AppInfoBitmap> newValues =new ArrayList<>();

                for (int i = 0; i < count; i++) {
                    //从ArrayList<AppInfoBitmap>中拿到AppInfoBitmap对象
                    final AppInfoBitmap value=values.get(i);

                    /*
                    * 这个地方是,要进行搜索的关键字,将app的name属性当作关键字来进行筛选
                    * */
                    final String valueText=value.getmName().toString().toLowerCase();

                    /*
                    * 首字符匹配:valueText.startsWith(prefixString)
                    * 输入的关键字包含在了某个item中:valueText.indexOf(prefixString.toString())!=-1
                    * */
                    if (valueText.startsWith(prefixString)|| valueText.indexOf(prefixString.toString())!=-1){
                        newValues.add(value);
                    }
                    else {
                        //处理首字符是空格,去掉text中的空格,然后赋值给字符串words
                        final  String[] words=valueText.split(" ");
                        //获取除去空格的字符串的长度
                        final int wordCount=words.length;

                        //Start at index 0,in case valueText starts with space(s)
                        for (int k = 0; k < wordCount; k++) {
                            if (words[k].startsWith(prefixString)){
                                //一旦找到匹配的就break,跳出for循环
                                newValues.add(value);
                                break;
                            }
                        }

                    }
                }

                //此时的results就是过滤后的List<AppInfoBitmap>
                results.values=newValues;
                results.count=newValues.size();
            }

            //将结果返回
            return results;
        }

        //筛选结果
        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
            //此时,Adapter数据源就是过滤后的esults
            mAppInfoList=(List<AppInfoBitmap>) filterResults.values;

            /*
             * 数据容器变化------->notifyDataSetInValidated
             * 容器中数据发生变化------->notifyDataSetChanged
             * */
            if (filterResults.count>0){
                //这个相当于从mAppInfoList中删除了一些数据,只是数据的变化,所以使用notifyDataSetChanged()
                notifyDataSetChanged();
            }else {

                //当results.count<=0,此时数据源就是重新new出来的,说明原始数据源已经失效了
                notifyDataSetInvalidated();
            }

        }
    }
}

 

 

下面是我的完整的Aadpter代码,希望可以帮助到陷入沉思的你。

public class AppListViewAdapter extends BaseAdapter implements Filterable{

    private Context mContext;

    //Adapter数据源
    private List<AppInfoBitmap> mAppInfoList;

    //过滤相关
    /*
    * 过滤器上的锁可以同步复制原始数据
    * */
    private final Object mLock=new Object();

    //对象数组的备份,当调用ArrayFilter的时候初始化和使用。此时,对象数组只包含已经过滤的数据。
    private ArrayList<AppInfoBitmap> mOriginalValues;
    private ArrayFilter mFilter;

    //带参构造
    public AppListViewAdapter(Context context, List<AppInfoBitmap> appInfoList) {
        this.mContext = context;
        this.mAppInfoList = appInfoList;
    }

    @Override
    public int getCount() {
        return mAppInfoList.size();
    }

    @Override
    public AppInfoBitmap getItem(int i) {
        return mAppInfoList.get(i);
    }

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

    //通过ViewHolder优化listView
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder=new ViewHolder();
        if (view==null){
            view=View.inflate(mContext, R.layout.activity_app_list_item,null);

            //获取布局控件
            viewHolder.imageView=view.findViewById(R.id.app_image);
            viewHolder.textView=view.findViewById(R.id.app_name);

            //设置布局控件
            viewHolder.imageView.setImageBitmap(mAppInfoList.get(i).getmBitmap());
            viewHolder.textView.setText(mAppInfoList.get(i).getmName());

            //设置Tag
            view.setTag(viewHolder);
        }else {
            //获取Tag
            viewHolder=(ViewHolder) view.getTag();

            //设置布局控件
            viewHolder.imageView.setImageBitmap(mAppInfoList.get(i).getmBitmap());
            viewHolder.textView.setText(mAppInfoList.get(i).getmName());
        }

        //将view视图返回
        return view;
    }

    public class ViewHolder{
        ImageView imageView;
        TextView textView;
    }

    @Override
    public Filter getFilter() {
        if (mFilter==null){
            mFilter=new ArrayFilter();
        }
        return mFilter;
    }

    //写一个ArrayFilter类继承Filter
    public class ArrayFilter extends Filter{

        //执行过滤的方法
        @Override
        protected FilterResults performFiltering(CharSequence charSequence) {
            /*
            * 一个带有首字母约束的数组过滤器,每一项
            * 不是以该首字母开头的都会被移除该list
            * */
            //过滤的结果
            FilterResults results=new FilterResults();

            //原始数据为空时,上锁,同步复制原始数据
            if (mOriginalValues==null){
                synchronized (mLock){
                    mOriginalValues=new ArrayList<>(mAppInfoList);
                }
            }

            //当首字母为空时
            if (charSequence==null||charSequence.length()==0){
                ArrayList<AppInfoBitmap> list;
                synchronized (mLock){
                    //同步复制一个原始备份数据
                    list=new ArrayList<>(mOriginalValues);
                }

                //此时返回的results就是原始的数据,不必进行过滤
                results.values=list;
                results.count=list.size();
            }else {
                //转化为小写
                String prefixString=charSequence.toString().toLowerCase() ;

                ArrayList<AppInfoBitmap> values;
                //同步复制一个原始备份数据
                synchronized (mLock){
                    values=new ArrayList<>(mOriginalValues);
                }

                final int count=values.size();
                final ArrayList<AppInfoBitmap> newValues =new ArrayList<>();

                for (int i = 0; i < count; i++) {
                    //从ArrayList<AppInfoBitmap>中拿到AppInfoBitmap对象
                    final AppInfoBitmap value=values.get(i);

                    /*
                    * 这个地方是,要进行搜索的关键字,将app的name属性当作关键字来进行筛选
                    * */
                    final String valueText=value.getmName().toString().toLowerCase();

                    /*
                    * 首字符匹配:valueText.startsWith(prefixString)
                    * 输入的关键字包含在了某个item中,位置不做考虑
                    * */
                    if (valueText.startsWith(prefixString)|| valueText.indexOf(prefixString.toString())!=-1){
                        newValues.add(value);
                    }
                    else {
                        //处理首字符是空格,去掉text中的空格,然后赋值给字符串words
                        final  String[] words=valueText.split(" ");
                        //获取除去空格的字符串的长度
                        final int wordCount=words.length;

                        //Start at index 0,in case valueText starts with space(s)
                        for (int k = 0; k < wordCount; k++) {
                            if (words[k].startsWith(prefixString)){
                                //一旦找到匹配的就break,跳出for循环
                                newValues.add(value);
                                break;
                            }
                        }

                    }
                }

                //此时的results就是过滤后的List<AppInfoBitmap>
                results.values=newValues;
                results.count=newValues.size();
            }

            //将结果返回
            return results;
        }

        //筛选结果
        @Override
        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
            //此时,Adapter数据源就是过滤后的esults
            mAppInfoList=(List<AppInfoBitmap>) filterResults.values;

            /*
             * 数据容器变化------->notifyDataSetInValidated
             * 容器中数据发生变化------->notifyDataSetChanged
             * */
            if (filterResults.count>0){
                //这个相当于从mAppInfoList中删除了一些数据,只是数据的变化,所以使用notifyDataSetChanged()
                notifyDataSetChanged();
            }else {

                //当results.count<=0,此时数据源就是重新new出来的,说明原始数据源已经失效了
                notifyDataSetInvalidated();
            }

        }
    }
}

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值