android自带的AutoCompleteTextView,可以简单地实现自动补全功能,但是限制较多 这里介绍如何通过自定义来扩展AutoCompleteTextView功能,包括以下功能
- 解决最小字符匹配数量限制,零个字符时也可提示全部选项
- 自定义匹配规则,可以自己通过代码实现拼音匹配,模糊匹配等功能
- 集成Adapter,不用再创建Adapter,直接传入一个选项数组即可
AutoCompleteEdit
//自动补全输入框
public class AutoCompleteEdit extends AppCompatAutoCompleteTextView {
private int threshold = 0;
private FilterableTextAdapter adapter;
public AutoCompleteEdit(Context context) {
super(context);
init();
}
public AutoCompleteEdit(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AutoCompleteEdit(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
//下拉项适配器
adapter = new FilterableTextAdapter();
adapter.autoCompleteEdit = this;
setAdapter(adapter);
//文字改变时,更新建议项
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) {
}
@Override
public void afterTextChanged(Editable s) {
adapter.getFilter().filter(s);
}
});
//获得焦点时,更新建议项
setOnFocusChangeListener((v, hasFocus) -> {
if (hasFocus)
showDropDown();
});
//有焦点重新点击时,也更新建议项
setOnClickListener(v -> {
if (getText().toString().isEmpty())
showDropDown();
});
}
@Override
public boolean enoughToFilter() {
return getText().length() >= threshold;
}
//设置字符匹配数量
public AutoCompleteEdit threshold(int threshold) {
this.threshold = threshold;
return this;
}
//更新全部可选数据
public AutoCompleteEdit reset(List datas) {
adapter.reset(datas);
return this;
}
//下拉选项更新时,执行回调
public AutoCompleteEdit onFilter(FilterableTextAdapter.OnFilter onFilter) {
adapter.onFilter((items, count) -> {
setDropDownHeight(600);
showDropDown();
});
return this;
}
}
FilterableTextAdapter
//带数据过滤功能的TextAdapter
public class FilterableTextAdapter extends BaseAdapter implements Filterable {
protected AutoCompleteEdit autoCompleteEdit;
private List originItems = new ArrayList();
private List filteredItems = new ArrayList();
private TextFilter filter = new TextFilter();
private OnFilter onFilter;
public void onFilter(OnFilter onFilter) {
this.onFilter = onFilter;
}
public int getCount() {
return filteredItems.size();
}
@Override
public String getItem(int position) {
return filteredItems.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View root = ViewManager.inflate(parent.getContext(), R.layout.item_text_list);
TextView text = root.findViewById(R.id.tv);
text.setText(getItem(position));
//点击设置文本,并关闭下拉框
root.setOnClickListener(v -> {
autoCompleteEdit.setText(text.getText());
autoCompleteEdit.setSelection(text.getText().length());
autoCompleteEdit.dismissDropDown();
});
return root;
}
@Override
public Filter getFilter() {
return filter;
}
//重置全部可选数据
public void reset(List items) {
originItems.clear();
originItems.addAll(items);
}
//文本过滤器,用于定义匹配规则,更新匹配项
public class TextFilter extends Filter {
//数据过滤
@Override
protected FilterResults performFiltering(CharSequence constraint) {
String key = constraint.toString().toLowerCase();
List temp = new ArrayList();
//如果没有限制,则显示全部
if (constraint.toString().isEmpty()) {
temp.addAll(originItems);
FilterResults results = new FilterResults();
results.values = temp;
results.count = temp.size();
return results;
}
//如果不是拼音,以关键字开头,或包含关键字,则匹配
for (String item : originItems) {
if (item.toLowerCase().startsWith(key))
temp.add(item);
}
for (String item : originItems) {
if (item.toLowerCase().contains(key) && !temp.contains(item))
temp.add(item);
}
//如果是拼音,拼音以关键字开头,或简拼以关键字开头,则匹配
if (key.matches("^[a-z]+$")) {
for (String item : originItems) {
if (TextUtil.getSimplePinyin(item).startsWith(key) && !temp.contains(item))
temp.add(item);
}
for (String item : originItems) {
if (TextUtil.getPinyin(item).contains(key) && !temp.contains(item))
temp.add(item);
}
}
//封装过滤结果
FilterResults results = new FilterResults();
results.values = temp;
results.count = temp.size();
return results;
}
//发布过滤结果
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
//根据过滤结果去更新adapter
if (results.count == 0)
notifyDataSetInvalidated();
else {
filteredItems = (List) results.values;
notifyDataSetChanged();
}
//执行回调
if (onFilter != null)
onFilter.OnFilter((List) results.values, results.count);
}
}
public interface OnFilter {
void OnFilter(List items, int count);
}
}
LoginActivity
public class LoginActivity extends CommonActivity {
@BindView(R.id.edit)
AutoCompleteEdit edit;
protected void create() {
setContentView(R.layout.activity_main);
ButterKnife.bind(this, ctx);
init();
}
private void init() {
List datas = new LinkedList();
datas.add("ABC");
datas.add("abc");
datas.add("中国人");
datas.add("abc中国人");
datas.add("中国人abc");
edit.reset(datas);
}
}
上面部分功能用到了工具类,需要自己修改,但是核心代码全部齐备,可以轻松修改
运行效果