自义定数据类型SearchView+listview搜索实现

来源:互联网 发布:超级红包群txt下载知新 编辑:程序博客网 时间:2024/05/16 12:40

listview中展示了多个我自己定义的student类,在搜索框中搜索关键字就能直接匹配到名字的功能,话不多说先上效果图:


本篇主要讲的是listview中自定义数据的展示中根据自己需求SearchView(搜索框)搜索的实现。

因为网上大部分写的都是单一的String的搜索。在有些场景并不适用,所以需要我们自己自定义搜索的功能。

1、先画布局 这里代码很简单我就只展示部分代码 activity_main布局中就只有searchview 和listview 两个控件。

 <SearchView        android:id="@+id/swarchview"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:iconifiedByDefault="false"        android:queryHint="@string/searchview"></SearchView>    <ListView        android:id="@+id/listview"        android:layout_width="match_parent"        android:layout_height="wrap_content"></ListView>

item的布局很简单就不给代码看了。

2、然后在mainactivity中找控件,初始化相关测试数据。找到SearchView控件后我们给它加上搜索文本监听的方法来监听(setOnQueryTextListener)搜索框中的文字的改变。

其中会要我们实现onQueryTextSubmit方法和onQueryTextChange方法,前者是当用户点击了搜索按钮后回调的 后者是当输入框内容改变时回调的。

3、然后在listview的适配器中定义一个自定义过滤器。在过滤器中我们自己来定义匹配规则,我是按name属性进行过滤。过滤器代码如下:

 //我们需要定义一个过滤器的类来定义过滤规则    class MyFilter extends Filter {        @Override        protected FilterResults performFiltering(CharSequence constraint) {            FilterResults result = new FilterResults();            List<StudentInfo> lists ;            if (TextUtils.isEmpty(constraint)){//当过滤的关键字为空的时候,我们则显示所有的数据                lists  = listdata;            }else {//否则把符合条件的数据对象添加到集合中                lists = new ArrayList<>();                for (StudentInfo recomend:list){                    if (recomend.getName().contains(constraint)){                        lists.add(recomend);                    }                }            }            result.values = lists; //将得到的集合保存到FilterResults的value变量中            result.count = lists.size();//将集合的大小保存到FilterResults的count变量中            return result;        }        @Override        protected void publishResults(CharSequence constraint, FilterResults results) {            list = (List<StudentInfo>)results.values;            if (results.count>0){                notifyDataSetChanged();//通知数据发生了改变            }else {                notifyDataSetInvalidated();//通知数据失效            }        }    }

4、然后让适配器实现Filterable接口实现getFilter()方法,在方法里面实例化刚刚创建的过滤器。核心代码如下:

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

5、回到我们的mainActivity中将listview设置文本监听不然到时候匹配不上的(listview.setTextFilterEnabled(treu))
然后在SearchView的监听方法中将输入的内容进行数据匹配 核心代码如下:

if (TextUtils.isEmpty(query)) {                    listView.clearTextFilter();//搜索文本为空时,清除ListView的过滤                }                else {                    listView.setFilterText(query);//设置过滤关键字                }

这样一个简单的自义定数据类型SearchView+listview搜索就实现了。
下面贴出全部代码:
MainActivity:

package com.example.administrator.searchviewdemo;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.text.TextUtils;import android.view.View;import android.widget.ArrayAdapter;import android.widget.ListAdapter;import android.widget.ListView;import android.widget.SearchView;import android.widget.Filter;import android.widget.Filterable;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity {    private SearchView searchView;    private ListView listView;    private List<StudentInfo> list;    private StudentAdapter adapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initViews();        initData();        initEvents();    }    private void initEvents() {        listView.setTextFilterEnabled(true);        // 设置搜索文本监听        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {            // 当点击搜索按钮时触发该方法            @Override            public boolean onQueryTextSubmit(String query) {                /*if (TextUtils.isEmpty(query)) {                    listView.clearTextFilter();//搜索文本为空时,清除ListView的过滤                }                else {                    listView.setFilterText(query);//设置过滤关键字                }*/                ListAdapter adapter = listView.getAdapter();                if (adapter instanceof Filterable) {                    Filter filter = ((Filterable) adapter).getFilter();                    if (query == null || query.length() == 0) {                        filter.filter(null);                    } else {                        filter.filter(query);                    }                }                return false;            }            // 当搜索内容改变时触发该方法            @Override            public boolean onQueryTextChange(String newText) {                ListAdapter adapter = listView.getAdapter();                if (adapter instanceof Filterable) {                    Filter filter = ((Filterable) adapter).getFilter();                    if (newText == null || newText.length() == 0) {                        filter.filter(null);                    } else {                        filter.filter(newText);                    }                }               /* if (!TextUtils.isEmpty(newText)){                    listView.setFilterText(newText);                }else{                    listView.clearTextFilter();                }*/                return false;            }        });        adapter = new StudentAdapter(this,list);        listView.setAdapter(adapter);    }    private void initData() {        list = new ArrayList<>();        list.add(new StudentInfo("张三",true,18));        list.add(new StudentInfo("李四",true,28));        list.add(new StudentInfo("王五",true,20));        list.add(new StudentInfo("六麻子",true,21));        list.add(new StudentInfo("秋水",true,25));        list.add(new StudentInfo("小红",false,21));        list.add(new StudentInfo("小白",true,25));        list.add(new StudentInfo("辛夷",true,26));        list.add(new StudentInfo("雏田",false,22));        list.add(new StudentInfo("鸣人",true,26));    }    private void initViews() {        listView = (ListView) findViewById(R.id.listview);        searchView = (SearchView) findViewById(R.id.swarchview);    }}

StudentAdapter适配器:

package com.example.administrator.searchviewdemo;import android.content.Context;import android.text.TextUtils;import android.util.Log;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.Filter;import android.widget.Filterable;import android.widget.TextView;import java.util.ArrayList;import java.util.List;/** * Created by Administrator on 2017/9/2. */public class StudentAdapter extends BaseAdapter implements Filterable{    private Context context;    private List<StudentInfo> list;    private List<StudentInfo> listdata;//备份原始数据    private MyFilter mFilter ;    public StudentAdapter(Context context, List<StudentInfo> list) {        this.context = context;        this.list = list;        this.listdata = list;    }    @Override    public int getCount() {        return list.size();    }    @Override    public Object getItem(int position) {        return list.get(position);    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        MyView myView=null;        if(convertView==null){            convertView = View.inflate(context,R.layout.listview_item,null);            myView = new MyView(convertView);            convertView.setTag(myView);        }else{            myView = (MyView) convertView.getTag();        }        myView.age.setText(list.get(position).getAge()+"岁");        myView.name.setText(list.get(position).getName());        if(list.get(position).isSex()) {            myView.sex.setText("男");        }else{            myView.sex.setText("女");        }        return convertView;    }    @Override    public Filter getFilter() {        if (mFilter ==null){            mFilter = new MyFilter();        }        return mFilter;    }    class MyView{        public TextView age,name,sex;        public MyView(View view) {            age = (TextView) view.findViewById(R.id.item_age);            name = (TextView) view.findViewById(R.id.item_name);            sex = (TextView) view.findViewById(R.id.item_sex);        }    }    //我们需要定义一个过滤器的类来定义过滤规则    class MyFilter extends Filter {        @Override        protected FilterResults performFiltering(CharSequence constraint) {            FilterResults result = new FilterResults();            List<StudentInfo> lists ;            if (TextUtils.isEmpty(constraint)){//当过滤的关键字为空的时候,我们则显示所有的数据                lists  = listdata;            }else {//否则把符合条件的数据对象添加到集合中                lists = new ArrayList<>();                for (StudentInfo recomend:list){                    if (recomend.getName().contains(constraint)){                        lists.add(recomend);                    }                }            }            result.values = lists; //将得到的集合保存到FilterResults的value变量中            result.count = lists.size();//将集合的大小保存到FilterResults的count变量中            return result;        }        @Override        protected void publishResults(CharSequence constraint, FilterResults results) {            list = (List<StudentInfo>)results.values;            if (results.count>0){                notifyDataSetChanged();//通知数据发生了改变            }else {                notifyDataSetInvalidated();//通知数据失效            }        }    }}


自定义数据类型我这里定义的是学生类(student):

public class StudentInfo {    private String name;    private boolean sex;    private int age;    public StudentInfo(String name, boolean sex, int age) {        this.name = name;        this.sex = sex;        this.age = age;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public boolean isSex() {        return sex;    }    public void setSex(boolean sex) {        this.sex = sex;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    @Override    public String toString() {        return "StudentInfo{" +                "name='" + name + '\'' +                ", sex=" + sex +                ", age=" + age +                '}';    }}

然后说说我在做这个搜索框的时候遇到的一些问题吧:
问题:就是当我在搜索框中输入后页面会出现黑色的弹窗显示我们输入的内容。我是不想要这个弹出窗的。
原因:本人通过看listview.setFilterText()的源码 发现系统回调这个方法时会调用 createTextFilter();方法来显示黑色的窗口。源代码如下:

/**     * Sets the initial value for the text filter.     * @param filterText The text to use for the filter.     *     * @see #setTextFilterEnabled     */    public void setFilterText(String filterText) {        // TODO: Should we check for acceptFilter()?        if (mTextFilterEnabled && !TextUtils.isEmpty(filterText)) {            createTextFilter(false);            // This is going to call our listener onTextChanged, but we might not            // be ready to bring up a window yet            mTextFilter.setText(filterText);            mTextFilter.setSelection(filterText.length());            if (mAdapter instanceof Filterable) {                // if mPopup is non-null, then onTextChanged will do the filtering                if (mPopup == null) {                    Filter f = ((Filterable) mAdapter).getFilter();                    f.filter(filterText);                }                // Set filtered to true so we will display the filter window when our main                // window is ready                mFiltered = true;                mDataSetObserver.clearSavedState();            }        }    }

所以我的思路就是跳过这个方法直接调用Filter.filter(filterText)方法,其中Filter是通过适配器得到。
解决:我们就在mainActivity中的SearchView的监听方法中改为如下代码:

 ListAdapter adapter = listView.getAdapter();                if (adapter instanceof Filterable) {                    Filter filter = ((Filterable) adapter).getFilter();                    if (newText == null || newText.length() == 0) {                        filter.filter(null);                    } else {                        filter.filter(newText);                    }                }


还有一个问题就是:
问题2:在搜索框输入时弹出的软键盘会将布局文件顶上去。
解决方法:在xml配置文件中找到相应的activity中添加android:windowSoftInputMode="adjustPan|stateHidden"
其中有参考了http://blog.csdn.net/zhangzeyuaaa/article/details/40187789这篇博客
如果有什么问题希望大家一起探讨一起进步,每天进步一小点。博主也是刚接触android的小白。
demo 下载:
GitHub