您的位置:首页 > 移动开发 > Android开发

Android开发学习笔记秘籍(十七)

2016-03-29 11:29 676 查看
今天学习下Filterable 和 EditText TextWatcher。

先说说效果---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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: