项目需求是用户登录界面,输入email的EditView里,弹出手机内保存的account list,使用户又可以手动输入,又可以直接从列表里选择。
首先搜到一个很棒的实现方法:带弹出列表的EditText。这篇博客尝试了两种方式实现:ListPopupWindow和AutoCompleteTextView。博主先用了后者,说特别是在横屏切换的时候不方便,最后选择了前者。自己真实尝试了之后,才发现自己的需求反而是后者=。= (没有好好理解博主意思的后果)
小白虽然源码也读的不是很明白,但AutoCompleteTextView的大概逻辑是:
watcher监控->检测到输入变化->performingFilter从可选列表里过滤出与输入匹配的list->弹出listPopupWindow
这样一看就明白了,autoCompleteTextView比listPopupWindow多了只显示匹配后的过程。估计那位博主没有这样的需求,只需要全部显示list。而我们这边的项目画面又不需要横屏,所以我们还是使用AutoCompleteTextView比较方便。
根据需求我们修改了原生代码的两个功能:
- 输入内容为空的时候也能弹出列表(源码虽然有可以设置输入长度的threshold,但必须长度大于0)
-->在调用部分增加onFocusChanged处理,且autoCompleteTextView里重载enoughToFilter()保证输入为空也会filter更新列表。
- 内容匹配不止是从头开始匹配,也实现中间的部分匹配
-->adapter里重载performingFilter()函数。匹配函数从原来的startwith(...)修改为contains(...)即可
重载AutoCompleteTextView:
public class InstantAutoCompleteTextView extends AutoCompleteTextView {
public InstantAutoCompleteTextView(Context context) {
super( context );
}
public InstantAutoCompleteTextView(Context context, AttributeSet attrs) {
super( context, attrs );
}
public InstantAutoCompleteTextView(Context context, AttributeSet attrs, int defStyle) {
super( context, attrs, defStyle );
}
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
if (focused && getAdapter() != null) {
performFiltering(getText(), KeyEvent.KEYCODE_UNKNOWN);
}
}
@Override
public boolean enoughToFilter() {
return true;
}
}
重载adapter部分,自定义performingFilter函数:
public class AutoCompleteAdapter<T> extends ArrayAdapter<T> implements Filterable {
private List<T> listObjects;
List<T> suggestions = new ArrayList<>();
private Filter mFilter = new Filter(){
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults filterResults = new FilterResults();
if(constraint != null) {
suggestions.clear();
for(T object : listObjects){
if(object.toString().toLowerCase().contains(constraint.toString().toLowerCase())){
suggestions.add(object);
}
}
filterResults.values = suggestions;
filterResults.count = suggestions.size();
}
return filterResults;
}
@SuppressWarnings( "unchecked" )
@Override
protected void publishResults(CharSequence contraint, FilterResults results) {
if(results == null){
notifyDataSetInvalidated();
return;
}
List<T> filteredList = (List<T>) results.values;
if(results.count > 0) {
clear();
for (T filteredObject : filteredList) {
add(filteredObject);
}
notifyDataSetChanged();
}
}
};
public AutoCompleteAdapter(Context context, int resource, List<T> listObjects) {
super(context, resource, listObjects);
this.listObjects =new ArrayList<>( listObjects );
}
@Override
public Filter getFilter() {
return mFilter;
}
}
实际调用代码片段:
public class MainActivity extends AppCompatActivity {
private InstantAutoCompleteTextView autoTextView;
private ArrayList<String> listArray;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initialize();
}
private void initialize(){
listArray=new ArrayList<>();
listArray.add("test 1");
listArray.add("test 2");
listArray.add("test 3");
listArray.add("default 9");
listArray.add("beautiful");
listArray.add("hello world");
listArray.add("boring sunday");
listArray.add("list test");
autoTextView=(InstantAutoCompleteTextView) findViewById(R.id.autoCompleteText);
AutoCompleteAdapter autocompleteAdapter = new AutoCompleteAdapter(this,android.R.layout.simple_list_item_1,listArray);
autoTextView.setAdapter(autocompleteAdapter);
}
}
最后test结果如下图(应用在项目里依然很完美!):
p.s. test的代码:
https://github.com/bingningO/AutoCompleteTextViewTest