Android中AutoCompleteTextView使用+自定义过滤规则

介绍如何使用AutoCompleteTextView,并自定义过滤规则

AutoCompleteTextView特性

  • AutoCompleteTextView是EditText的子类,可以使用EditText所有的属性
  • 用于输入框的自动完成提示,非常适合搜索框。
  • setThreshold:指定用户至少输入几个字符才会显示提示

常规的简单实现

  • 设置AutoCompleteTextView的适配器为ArrayAdapter,ArrayAdapter已经实现了Filterable接口。此时,只要给AutoCompleteTextView添加文字监听:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private String[] autostr = new String[] { "a", "ab", "abc",
"abcd", "b", "bc", "bcd" };
//android.R.layout.simple_dropdown_item_1line是系统自带的简单item布局
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_dropdown_item_1line, autostr);
mAutoCompleteTv.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) {
//只需添加这一句代码即可
//这句话的意思是为AutoCompleteTextView设置过滤字段为s,只要数据是以s开头,都会显示出来
adapter.getFilter().filter(s);
}
@Override
public void afterTextChanged(Editable s) {
}
});

自定义过滤规则

  • 要自己定义过滤规则,主要是对Filterable接口的实现,其他部分与ListView的适配器设置并无区别。

  • 下面给出一个实例,实现的效果是:在输入框输入字符串s,只要某条数据里含有s,就将该条数据显示出来。关键代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
相关变量
-------------------------------------------------------------------------------------------------
private AutoCompleteTextView mAutoCompleteTv;
//这个一旦赋值就不会改变了,相当数据库的概念,是搜索的数据源,也就是说展示的list数据是根据定义
//的过滤规则,从mSearchDataBaseList中取出符合过滤规则的数据。
//这个mSearchDataBaseList一般是从后台获取。
private List<String> mSearchDataBaseList = new ArrayList<>();
//这个是搜索的结果集合,随搜索内容而改变
private List<String> mSearchResultList = new ArrayList<>();//
private MyAutoCompleteTvAdapter mAutoCompleteTvAdapter;
设置适配器
---------------------------------------------------------------------------------------
mAutoCompleteTvAdapter = new MyAutoCompleteTvAdapter(getApplicationContext(), mSearchResultList);
mAutoCompleteTv.setAdapter(mAutoCompleteTvAdapter);
适配器的具体实现
-----------------------------------------------------------------------------------------
class MyAutoCompleteTvAdapter extends BaseAdapter implements Filterable {
private Context context;
//该list存放的是最终弹出列表的数据
private List<String> list = new ArrayList<>();
private MyAutoCompleteTvAdapter(Context context, List<String> list) {
this.context = context;
this.list = list;
}
@Override
public Filter getFilter() {
Filter filter = new Filter() {
/**
* 在后台线程执行,定义过滤算法
* @param constraint :就是你在输入框输入的字符串
* @return 符合条件的数据结果,会在下面的publishResults方法中将数据传给list
*/
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (constraint == null || constraint.length() == 0) {
//
results.values = mSearchDataBaseList;
results.count = mSearchDataBaseList.size();
} else {
//这个newList是实际搜索出的结果集合,实际上是将该newList的数据赋给了list
List<String> newList = new ArrayList<>();
for (String s : mSearchDataBaseList) {
//包含就添加到newList中
if (s.contains(constraint.toString().trim()
)) {
newList.add(s);
}
}
//将newList传给results
results.values = newList;
results.count = newList.size();
newList = null;
}
return results;
}
/**
* 本方法在UI线程执行,用于更新自动完成列表
* @param constraint
* @param results
*/
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {//有符合过滤规则的数据
list.clear();
list.addAll((List<String>) results.values);
notifyDataSetChanged();
} else {//没有符合过滤规则的数据
notifyDataSetInvalidated();
}
}
/**
* 将符合条件的数据转换为你想要的方式,一般无需实现
* 控制用户点击提示时要填充至输入框的文本内容。
*/
@Override
public CharSequence convertResultToString(Object resultValue) {
return super.convertResultToString(resultValue);
//假如这里写 return "啊哈哈";
//那么,无论你点击哪个条目,出现在输入框的永远是"啊哈哈"这几个字。
}
};
return filter;
}
@Override
public int getCount() {
return list != null && list.size() > 0 ? list.size() : 0;
}
/**
* 这里必须返回list.get(position),否则点击条目后输入框显示的是position,而非该position的数据
*
* @param position
* @return
*/
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
TvViewHolder holder;
if (convertView == null) {
convertView = View.inflate(context, R.layout.item_autocompletetv_simple_dropdown, null);
holder = new TvViewHolder();
holder.tv = (TextView) convertView.findViewById(R.id.text1);
convertView.setTag(holder);
} else {
holder = (TvViewHolder) convertView.getTag();
}
//注意这里不要为convertView添加点击事件,默认是点击后:①下拉窗收起;
//②点击的条目数据会显示在搜索框中;③光标定位到字符串末位。
//如果自己添加点击事件,就要首先实现上面的①、②、③。
holder.tv.setText(list.get(position));
return convertView;
}
class TvViewHolder {
TextView tv;
}
}
布局文件,很简单,只有一个textview
------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<TextView android:id="@+id/text1"
style="?android:attr/dropDownItemStyle"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:ellipsize="marquee"
android:padding="12dp"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceLargePopupMenu"
android:textColor="#8e8d8d"/>