Android开发学习笔记秘籍(十七)
2016-03-29 11:29
676 查看
今天学习下Filterable 和 EditText TextWatcher。
先说说效果---EditText中输入内容,在ListView中筛选出与内容对应的内容。这个效果就相当于是手机通讯录搜索功能,就比如你输入一个联系人的名字,能过滤掉其他联系人,最后显示与你输入相对应的联系人。
界面十分的简单就是一个EditText+一个ListView,代码如下:
既然要实现联系人的过滤器,那就得有联系人这个类。创建一个联系人的类--Person.java,定义两个变量personName、personNumber分别对应联系人姓名和联系人电话号码。代码如下:
我这里还定义了一个isSelected是为了让选中看上去明显一点对这个效果并没有影响,不用也是可以的!
接下来就是MainActivity了。在MainActity中只需要做三件事--初始化Person类型数组的初始数据,初始化视图,初始化控件(即适配器、点击事件的设置)。代码如下:
这里有使用到EditText中的TextWatcher,等等和适配器中的Filter一起解释。
然后就是ListView的自定义适配器了--MyAdapter,先贴代码再学习。
在MyAdapter中如何加载View的数据,去搜大神们写的东西吧http://stackvoid.com/using-adapter-in-efficiency-way/类似这样的文章很多,甚至有的大神还进行了内存、时间上的测试,这里学习下Filterable中要学习的东西。先学习下API中对Filterable的介绍。
Filterable定义了一种可过滤行为,Filterable接口通常有android.widget.Adapter来实现。接口Filterable中有个抽象方法getFilter()需要实现。getFilter()返回一个filter对象,用来过滤出符合要求的数据。getFilter()方法通常在adapter 中实现。本例即是如此MyAdapter实现了接口Filterable,之后就必须实现getFilter()。
Filter通常是实现Filterable接口来创建Filter对象,方法filter(CharSequence)、filter(CharSequence, FilterListener)实现过滤操作是异步进行的。将一个过滤请求放到请求队列中,在稍候处理。取消上次没有执行的过滤请求。创建一个Filter对象,需要至少实现两个抽象方法:
protected FilterResults performFiltering(CharSequence constraint)
protected void publishResults(CharSequence constraint, FilterResults results)
方法一:
protected FilterResults performFiltering(CharSequence constraint)
在worker线程中调用,依据constraint来过滤。返回结果,一个FilterResults对象,将通过方法publishResults(Charsequence, FilterResults)在UI线程中发表。
当参数(constraint)为null,恢复为初始的数据。
方法二:
protected void publishResults(CharSequence constraint, FilterResults results)
在UI线程中调用。发表过滤操作的结果显示到UI中。
现在看看效果是如何在代码中实现的,我们在EditText中输入字符,比如说输入‘w’,这时候由于EditText中内容改变,调用onTextChanged,而在代码中我们又执行了Filter的操作,根据上面API的解释会在performFiltering中去处理,最后返回一个result。在上面代码中正是处理过滤操作的。循环所有的Persion,若其名字中包含输入的字符,那我们就将其保存在一个_filterPersons 数组中去,结果返回的result就是_filterPersons的数据,然后在publishResults中同步到UI线程中去(这里的notifyDataSetChanged好像会导致效率很低,具体的没有研究过),最后就能出现文章开始的那个效果了。
再来说说我犯的一些错误,我们在performFiltering中是通过循环遍历整个Person数组来完成过滤操作的,之前我并不是这么做的,我选择遍历已过滤的Person数组即persons这个数组,的确当我们持续输入的时候确实可以过滤成功,但问题出现在你删除字符后,比如你EditText中的字符现在是weibo,按道理你删除“bo”,listview中必须显示两条数据,可最后还是只显示了一条,你只有删光所有的重新输入wei才出现两条,这个问题就错在你循环遍历的对象上了,你循环遍历的对象是已过滤数组_filterPersons,当你输入weibo的时候,它自然只剩下一条记录,你再删字符它遍历的还是这一条记录所以你只能看到一条记录,那有人问你删光了再输为什么就有呢,因为删光了会使resultData变成全部的Persons,在publisResults中更新UI会加载所有的Persons,你这时候在输入它遍历的就是全部的数据,自然就能显示俩条。具体的流程你可以下载我的源码来看,我在关键的地方都下了Log。最后Fliterable的学习就到这里了。
源码链接:http://download.csdn.net/detail/cuihaoren01/9475301
先说说效果---EditText中输入内容,在ListView中筛选出与内容对应的内容。这个效果就相当于是手机通讯录搜索功能,就比如你输入一个联系人的名字,能过滤掉其他联系人,最后显示与你输入相对应的联系人。
界面十分的简单就是一个EditText+一个ListView,代码如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <EditText android:id="@+id/my_edit" android:layout_width="match_parent" android:layout_height="wrap_content" /> <ListView android:id="@+id/my_list" android:layout_width="match_parent" android:layout_height="wrap_content"> </ListView> </LinearLayout>
既然要实现联系人的过滤器,那就得有联系人这个类。创建一个联系人的类--Person.java,定义两个变量personName、personNumber分别对应联系人姓名和联系人电话号码。代码如下:
public class Person { private String personName; private String personNumber; private boolean isSelected; /** * @param personName * @param personNumber */ public Person(String personName, String personNumber){ this.personName = personName; this.personNumber = personNumber; } public String getPersonName() { return personName; } public void setPersonName(String personName) { this.personName = personName; } public String getPersonNumber() { return personNumber; } public void setPersonNumber(String personNumber) { this.personNumber = personNumber; } public boolean isSelected() { return isSelected; } public void setSelected(boolean selected) { isSelected = selected; } }
我这里还定义了一个isSelected是为了让选中看上去明显一点对这个效果并没有影响,不用也是可以的!
接下来就是MainActivity了。在MainActity中只需要做三件事--初始化Person类型数组的初始数据,初始化视图,初始化控件(即适配器、点击事件的设置)。代码如下:
import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; import android.widget.EditText; import android.widget.ListView; import com.example.cui.filtertest.adapter.MyAdapter; import com.example.cui.filtertest.model.Person; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { EditText my_edit; ListView my_list; List<Person> persons = new ArrayList<>(); MyAdapter myAdapter = new MyAdapter(this, persons); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData();//初始化联系人信息 initView();//初始化视图 initComponent();//初始化控件 } private void initData(){ persons.add(new Person("wuyuetian","1254315412")); persons.add(new Person("panweibo ","4831843512")); persons.add(new Person("zhoujielun","7413543131")); persons.add(new Person("wanglihong","3412313231")); persons.add(new Person("dongfangshenqi","7654631130")); persons.add(new Person("Bigbang","4616843613")); persons.add(new Person("EXo","9461346416")); persons.add(new Person("taofenboy","4846132031")); persons.add(new Person("guobin","8946131313")); persons.add(new Person("liguangyuan","9846131106")); persons.add(new Person("zhengweiri","6931543613" )); } private void initView(){ my_edit = (EditText)findViewById(R.id.my_edit); my_list = (ListView)findViewById(R.id.my_list); } private void initComponent(){ my_list.setAdapter(myAdapter); my_edit.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { myAdapter.getFilter().filter(s); // Log.i("TAG我的天啊","你特么到底是怎么执行的?"); } @Override public void afterTextChanged(Editable s) { } }); } }
这里有使用到EditText中的TextWatcher,等等和适配器中的Filter一起解释。
然后就是ListView的自定义适配器了--MyAdapter,先贴代码再学习。
import android.content.Context; import android.util.Log; import android.view.LayoutInflater; 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 com.example.cui.filtertest.R; import com.example.cui.filtertest.model.Person; import java.util.ArrayList; import java.util.List; /** * Created by user on 2016/3/28. */ public class MyAdapter extends BaseAdapter implements Filterable { private Context context; private List<Person> persons; private List<Person> filterPersons; public MyAdapter(Context context, List<Person> persons) { this.context = context; this.persons = persons; this.filterPersons = persons; } private class ViewHolder{ TextView personName, personNumber; } @Override public int getCount() { return null == persons ? 0:persons.size(); } @Override public Object getItem(int position) { return persons.get(position); } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; LayoutInflater mInflater =LayoutInflater.from(context); if (convertView == null){ convertView = mInflater.inflate(R.layout.list_item,null); holder = new ViewHolder(); holder.personName = (TextView) convertView.findViewById(R.id.per_name); holder.personNumber = (TextView) convertView.findViewById(R.id.per_number); convertView.setTag(holder); }else{ holder = (ViewHolder)convertView.getTag(); } final Person item = (Person)getItem(position); holder.personName.setText(item.getPersonName()); holder.personNumber.setText(item.getPersonNumber()); if(item.isSelected()){ convertView.setBackgroundColor(context.getResources().getColor(R.color.colorPrimary)); }else { convertView.setBackgroundColor(context.getResources().getColor(R.color.white)); } final View view = convertView; view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { item.setSelected(item.isSelected() ? false : true); if(item.isSelected()){ view.setBackgroundColor(context.getResources().getColor(R.color.colorPrimary)); }else { view.setBackgroundColor(context.getResources().getColor(R.color.white)); } } }); Log.i("TAG", "I have executed getView()"); return convertView; } @Override public Filter getFilter() { return new Filter() { @Override protected FilterResults performFiltering(CharSequence constraint) { FilterResults resultData = new FilterResults(); if(constraint != null && constraint.length() > 0){ ArrayList<Person> _filterPersons = new ArrayList<>(); for (int i = 0; i < filterPersons.size(); i++){ Person filterableCustomer = filterPersons.get(i); if(filterableCustomer.getPersonName().toLowerCase() .contains(constraint.toString().toLowerCase())){ _filterPersons.add(filterableCustomer); Log.i("快快快","让我看看你特么是怎么变的" + constraint); } Log.i("这里有","执行到吗"); } resultData.count = _filterPersons.size(); resultData.values = _filterPersons; Log.i("为啥我删了字符后","你为啥不变啊"); }else{ resultData.values = filterPersons; resultData.count = filterPersons.size(); } Log.i("TAG","constraint:" + constraint); Log.i("TAG", "resultData:" + resultData.values.toString()); return resultData; } @Override protected void publishResults(CharSequence constraint, FilterResults results) { persons = (ArrayList<Person>)results.values; notifyDataSetChanged(); } }; } }
在MyAdapter中如何加载View的数据,去搜大神们写的东西吧http://stackvoid.com/using-adapter-in-efficiency-way/类似这样的文章很多,甚至有的大神还进行了内存、时间上的测试,这里学习下Filterable中要学习的东西。先学习下API中对Filterable的介绍。
Filterable定义了一种可过滤行为,Filterable接口通常有android.widget.Adapter来实现。接口Filterable中有个抽象方法getFilter()需要实现。getFilter()返回一个filter对象,用来过滤出符合要求的数据。getFilter()方法通常在adapter 中实现。本例即是如此MyAdapter实现了接口Filterable,之后就必须实现getFilter()。
Filter通常是实现Filterable接口来创建Filter对象,方法filter(CharSequence)、filter(CharSequence, FilterListener)实现过滤操作是异步进行的。将一个过滤请求放到请求队列中,在稍候处理。取消上次没有执行的过滤请求。创建一个Filter对象,需要至少实现两个抽象方法:
protected FilterResults performFiltering(CharSequence constraint)
protected void publishResults(CharSequence constraint, FilterResults results)
方法一:
protected FilterResults performFiltering(CharSequence constraint)
在worker线程中调用,依据constraint来过滤。返回结果,一个FilterResults对象,将通过方法publishResults(Charsequence, FilterResults)在UI线程中发表。
当参数(constraint)为null,恢复为初始的数据。
方法二:
protected void publishResults(CharSequence constraint, FilterResults results)
在UI线程中调用。发表过滤操作的结果显示到UI中。
现在看看效果是如何在代码中实现的,我们在EditText中输入字符,比如说输入‘w’,这时候由于EditText中内容改变,调用onTextChanged,而在代码中我们又执行了Filter的操作,根据上面API的解释会在performFiltering中去处理,最后返回一个result。在上面代码中正是处理过滤操作的。循环所有的Persion,若其名字中包含输入的字符,那我们就将其保存在一个_filterPersons 数组中去,结果返回的result就是_filterPersons的数据,然后在publishResults中同步到UI线程中去(这里的notifyDataSetChanged好像会导致效率很低,具体的没有研究过),最后就能出现文章开始的那个效果了。
再来说说我犯的一些错误,我们在performFiltering中是通过循环遍历整个Person数组来完成过滤操作的,之前我并不是这么做的,我选择遍历已过滤的Person数组即persons这个数组,的确当我们持续输入的时候确实可以过滤成功,但问题出现在你删除字符后,比如你EditText中的字符现在是weibo,按道理你删除“bo”,listview中必须显示两条数据,可最后还是只显示了一条,你只有删光所有的重新输入wei才出现两条,这个问题就错在你循环遍历的对象上了,你循环遍历的对象是已过滤数组_filterPersons,当你输入weibo的时候,它自然只剩下一条记录,你再删字符它遍历的还是这一条记录所以你只能看到一条记录,那有人问你删光了再输为什么就有呢,因为删光了会使resultData变成全部的Persons,在publisResults中更新UI会加载所有的Persons,你这时候在输入它遍历的就是全部的数据,自然就能显示俩条。具体的流程你可以下载我的源码来看,我在关键的地方都下了Log。最后Fliterable的学习就到这里了。
源码链接:http://download.csdn.net/detail/cuihaoren01/9475301
相关文章推荐
- Android图表第三方库enginechart的使用小结
- 【Android基础】Android代码混淆详解
- Android里如何让DialogFragment的宽度顶满屏幕?
- Android开发——Android Studio使用新的Gradle构建工具配置NDK环境
- Android fragment 重叠问题的解决方法
- Android 使用xml定义Drawable--第一篇:概述以和Shape Drawable示例
- android中id与+id
- mac配置android和maven环境变量
- Android开发IDE插件集合----selector
- android ViewHolder简洁写法 实用
- 关于android中的通信方式
- AndroidManifest.xml
- Android中dp,px,sp概念
- Android四大组件之BroadcastReceiver
- Android 多重CPU兼容的注意事项
- 欢迎使用CSDN-markdown编辑器
- Android 获取View的宽高
- Android Studio NDK开发
- [Android基础]Android总结篇
- Androidstudio点9图报错