项目中或多或少都要用到输入框。而对于输入框来说,用户想要的最好的体验莫过于输入部分文字后即可选择自动填充。
但是问题来了,安卓中给用户提供的控件AutoCompleteTextView或者MultiAutoCompleteTextView并不能很方便的进行模糊查询。必须要在首字符满足的情况下才能出现结果,而且想自定义也很麻烦。我看了半天的源码,也没有更改好自己想要实现的模糊查询。
所以我就想到使用PopWindow+ListView的方式制造自定义的
自动填充文本框,即AutoText;
先上效果图
输入文字
选择相应的item
不同效果的短信的模糊搜索
接下来看代码:
MyAutoText.java
进行数据初始化和查询等操作
/**
* Created by 实现自动填充的EditText
*/
public class MyAutoText implements DeliverData{
//保存查询到的数据
private ArrayList<String> myList = new ArrayList<>();
//获取用户提供的list数据
private ArrayList<String> list;
//获取输入框EditText
private EditText editText;
//获取Activity(因为window必须依赖于Activity)
private Activity activity;
//listview的适配器
private ListViewAdapter adapter;
//显示查询数据的listview
private ListView listView;
//popwindow
private PopupWindow popupWindow;
public MyAutoText(Activity activity, EditText editText, ArrayList<String> list) {
this.activity = activity;
this.editText = editText;
this.list = list;
initdata();
}
//数据初始化
private void initdata(){
adapter = new ListViewAdapter(activity,this);
setPopWindow();
setListener();
}
//为edidtetx添加字符变化的监听事件
private void setListener() {
editText.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) {
//每次查询前清除上一次查询内容
if (myList != null) {
myList.clear();
}
//对字符长度进行检索
if(s.length()>0){
search(String.valueOf(s));
}else{
adapter.setData(null,null);
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
}
//对用户传递的list进行查询操作
private void search(String s) {
for (String str : list) {
if (str.contains(s)) {
myList.add(str);
}
}
//刷新adapter
adapter.setData(myList, s);
//显示popwindow
popupWindow.showAsDropDown(editText);
}
//设置popwindow
private void setPopWindow() {
LayoutInflater inflater = LayoutInflater.from(activity);
LinearLayout root = (LinearLayout) inflater.inflate(R.layout.autotext_popwindow, null);
listView = (ListView) root.findViewById(R.id.autotext_popwindow_listview);
listView.setAdapter(adapter);
popupWindow = new PopupWindow();
popupWindow.setWidth(editText.getWidth());
popupWindow.setHeight(200);
popupWindow.setContentView(root);
}
//接口回调,获取listview点击事件后给EditText传值
@Override
public void deliverData(String data) {
editText.setText(data);
popupWindow.dismiss();
}
}
ListViewAdapter
这里没有什么难处,唯一就是需要接口回调数据
/**
* 适配器
*/
public class ListViewAdapter extends BaseAdapter{
private ArrayList<String> list=new ArrayList<>();
private Activity activity;
private String str; //查询的关键字
private DeliverData deliverData;
public ListViewAdapter(Activity activity,DeliverData deliverData) {
this.activity=activity;
this.deliverData=deliverData;
}
@Override
public int getCount() {
if(list!=null){
return list.size();
}else{
return 0;
}
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView text=new TextView(activity);
text.setTextSize(18);
text.setText(list.get(position)+"");
text.setId(position);
text.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//给AutoText回调选中的数据
deliverData.deliverData(list.get(v.getId()));
}
});
return text;
}
//刷新adapter数据
public void setData(ArrayList<String> list,String search){
this.list=list;
this.str=search;
this.notifyDataSetChanged();
}
}
DeliverData
创建一个接口,进行数据转发
/**
* Created by 转发的数据
*/
public interface DeliverData {
void deliverData(String data);
}
总结:
这种方式实现起来其实很简单。它最大的好处是模糊查询,你可以自定义自己要搜索的形式。你可以选择单一的号码。也可以选择展示带有描述的图片等等。而我觉得有一点瑕疵就是我:
没有自定义用户查询的关键字样式。style。如果说有需要的话可以自己自定义一下。
//然后这里解释一下我遇到的popwindow问题:
popwindow可能在Activity未创建完成的时候就加载。这时候可能会报一个
unable to add the window 的错误信息。
如果出现。用一个线程延迟加载就行了。