Android 自定义过滤搜索框 filterable

简单的说就是ListView上面有一个SearchBox,然后searchbox里输入内容后对下面listview进行过滤。

涉及的控件:ListView必须有,EditText用来自定义SearchBox

大概就是这样:

 

 

 

 

先看这个有图片的EditText,实现方法有两个,一是用相对布局RelativeLayout + ImageView + EditText。

二是直接用EditText的一个属性DrawableLeft,简单的UI这个就可以实现了

所以这个Activity的布局就很简单,可以用ListActivity实现:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <EditText
        android:id="@+id/searchbox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:drawableLeft="@drawable/searchbox"
        android:hint="Search"
        android:drawablePadding="5dp"
        android:singleLine="true"
        android:ems="10" >
        <requestFocus />
    </EditText>

    
    <ListView 
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/searchbox">
    </ListView>
 
</RelativeLayout>

 

再说过滤功能:这个感觉不想搜索,就像是简单的过滤,如果涉及到去数据库取数据那个才是搜索了

用到了Filterable接口,Filter类

要让数据有过滤功能,我们需要在继承的BaseAdapter的基础上再实现Filterable接口的getFilter方法,同时在Adapter内部写一个继承Filter的内部类来完成过滤功能:

private class ListAdapter extends BaseAdapter implements Filterable {

		private List<Person> list;
		
		private Context context;
		
		private PersonFilter filter;
		
		public ListAdapter(List<Person> list, Context context) {
			this.list = list;
			this.context = context;
		}

		@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) {
			if (convertView == null) {
				convertView = LayoutInflater.from(context).inflate(R.layout.list_item, null);
			}
			Person p = list.get(position);
			TextView firstname = (TextView)convertView.findViewById(R.id.firstname);
			TextView lastname = (TextView)convertView.findViewById(R.id.lastname);
			TextView age = (TextView)convertView.findViewById(R.id.age);
			
			firstname.setText(p.firstname);
			lastname.setText(p.lastname);
			age.setText(p.age + "");
			return convertView;
		}

		@Override
		public Filter getFilter() {
			if (filter == null) {
				filter = new PersonFilter(list);
			}
			return filter;
		}
		
		private class PersonFilter extends Filter {
			
			private List<Person> original;
			
			public PersonFilter(List<Person> list) {
				this.original = list;
			}

			@Override
			protected FilterResults performFiltering(CharSequence constraint) {
				FilterResults results = new FilterResults();
				if (constraint == null || constraint.length() == 0) {
					results.values = original;
					results.count = original.size();
				} else {
					List<Person> mList = new ArrayList<Person>();
					for (Person p: original) {
						if (p.firstname.toUpperCase().startsWith(constraint.toString().toUpperCase())
							|| p.lastname.toUpperCase().startsWith(constraint.toString().toUpperCase())
							|| new String(p.age + "").toUpperCase().startsWith(constraint.toString().toUpperCase())) {
							mList.add(p);
						}
					}
					results.values = mList;
					results.count = mList.size();
				}
				return results;
			}

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

 Filter类中的两个方法看名字就是知道一个是执行过滤的,一个刷新listview数据展现结果的。其中我采用了前缀匹配,就是用输入的字符串和ListView里的所有Person的各个属性的前缀做比较。也可以用更加复杂的匹配,例如正则表达式。

关键在于EditText里的数据是如何传入的,要写一个TextWater,并且要让EditText注册一下这个监听器:

        private TextWatcher filterTextWatcher = new TextWatcher() {

		@Override
		public void afterTextChanged(Editable s) {

		}

		@Override
		public void beforeTextChanged(CharSequence s, int start, int count,
				int after) {

		}

		@Override
		public void onTextChanged(CharSequence s, int start, int before,
				int count) {
			listAdapter.getFilter().filter(s); //这里传入数据就可以了
		}

	};

 以上关键代码。非关键代码是Person类以及List_Item的布局:

        private class Person {
		public String firstname;
		public String lastname;
		public int age;
		
		public Person(String firtname, String lastname, int age) {
			this.firstname = firtname;
			this.lastname = lastname;
			this.age = age;
		}
	}

 List_Item布局:

<?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="horizontal" >

    <TextView
        android:id="@+id/firstname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="Firstname" />

    <TextView
        android:id="@+id/lastname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="Lastname" />
    
    <TextView
        android:id="@+id/age"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="Age" />

</LinearLayout>

 

/home/wangjianhua/Desktop/1365932013_4825.jpg

posted @ 2015-09-23 16:11  williamgufeng  阅读(1158)  评论(0编辑  收藏  举报