AutoCompleteTextView继承自TextView,是一种可以实现自动补全的功能的TextView。先看效果:
该功能在目前很常见,例如在用户进行登录的时候或者注册的时候都用到了这种功能,在Android中这样的效果我们可以借助AutoComleteTextView来实现。
为了实现补全功能AutoCompleteTextView需要和Adapter(适配器)一起使用。Android为我们封装好了一些简单的适配器可以直接使用,当然我们也可以使用自定义的适配器来进行补充。
先从简单的开始,我们直接使用Android系统为我们提供的适配器来实现补全功能:
1、 先在xml文件中添加AutoCompleteTextView控件
<AutoCompleteTextView
android:id="@+id/autoCompeteTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入用户名"
android:inputType="number"/>
注意inputType属性是在这里申明了该控件只接受数字型的数据输入。
2、在java文件中申明并获取该控件
private AutoCompleteTextView autoCompleteTextView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_atctextview);
autoCompleteTextView = (AutoCompleteTextView)findViewById(R.id.autoCompeteTextView);
}
3、为AutoCompleteTextView设置适配器
autoCompleteTextView.setThreshold(1);
ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,test);
autoCompleteTextView.setAdapter(adapter);
setThreshold()方法是设置当用户输入多少字符时开始进行提示,不写这个方法也行,默认的设置为2。
在new ArrayAdapter时需要传入三个参数。
第一个参数是当前的上下文,暂且不提。
第二个参数是显示提示时的View,在这里我们传入的是系统为我们提供好的一个xml布局文件,在该xml布局文件里只有一个TextView控件。
第三个参数是我们设置的提示数据,当用户的输入和我们传入的提示数据匹配时,才会出现补全提示。
在这里我设置的提示数据是一个String数组
private String[] test = {"123","234","345","456"};
整体代码如下:
private AutoCompleteTextView autoCompleteTextView;
private String[] test = {"123","234","345","456"};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_atctextview);
autoCompleteTextView = (AutoCompleteTextView)findViewById(R.id.autoCompeteTextView);
autoCompleteTextView.setThreshold(1);
ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1,test);
autoCompleteTextView.setAdapter(adapter);
}
效果图:
当然看到这里我们会发现,虽然已经实现了补全功能了,但是和我们需求的功能还是差了一些,因此为了实现最开始的补全效果,我们需要自己设计一个Adapter来实现。
前面两个步骤都是一样的,只不过在第三步里我们需要使用自己定义的Adapter完成。
为了实现自定义Adapter我们需要继承BaseAdapter类并重写该类里4个抽象方法
class MyAdpater extends BaseAdapter{
@Override
public int getCount() {
return 0;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
}
当然,到这里远远还是不够了,继承了BaseAdapter,我们只是实现了一个基础的Adapter的功能,为了实现补全,我们还需要实现一个Filterable接口,并实现该接口里的getFilter抽象方法
class MyAdpater extends BaseAdapter implements Filterable{
@Override
public int getCount() {
return 0;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
@Override
public Filter getFilter() {
return null;
}
}
getFilter()方法会返回一个Filter对象,Filter是一个数据过滤器,其过滤操作是通过performFiltering()方法和publishResult()方法完成的。(当然一旦我们实现该类,我们也必须重写这两个方法)。performFiltering方法进行过滤操作,publishResult方法用于发表过滤操作结果。
public Filter getFilter() {
Filter filter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
return null;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
}
};
return filter;
}
先看preformFiltering()方法,在这个方法中我们需要实现过滤数据的操作。即:在补全里显示什么数据是在这个方法里决定的。performFiltering方法传递过来的参数constraint即为用户的输入,我们在这个方法中只需要将用户输入与一开始设置好的邮箱后缀结合在一起。并将数据封装在FilterResults里,由系统传递给publishResults方法进行发表。
private String[] emails = {"@qq.com","@163.com","@sina.com","@gmail.com"};
private ArrayList data = new ArrayList<>();
public Filter getFilter() {
Filter filter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
ArrayList newData = new ArrayList<>();
if(constraint != null && !constraint.toString().contains("@")){
for(String data : emails){
newData.add(constraint+data);
}
}
results.values = newData;
results.count = newData.size();
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
data = (ArrayList)results.values;
notifyDataSetChanged();
}
};
return filter;
}
到这里我们就将提供给用户的补全数据准备好了,剩下的就是在将这些数据显示出来展示给用户看和选择。重写Adapter的getView方法
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView;
if(convertView == null){
textView = new TextView(ATCTextViewActivity.this);
}else{
textView = (TextView)convertView;
}
textView.setText(data.get(position));
return textView;
}
在getView方法中,创建一个TextView对象用于显示数据。
最后就是将自定义Adapter设置给AutoCompleteTextView。以下是自定义Adapter的完整代码
class MyAdapter extends BaseAdapter implements Filterable{
//除了直接定义数组之外还可以从资源文件中获取数组,获取res/values/arrays文件中数组
//private String[] emails = getResources().getStringArray(R.array.emails);
private String[] emails = {"@qq.com","@163.com","@sina.com","@gmail.com"};
private ArrayList data = new ArrayList<>();
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView;
if(convertView == null){
textView = new TextView(ATCTextViewActivity.this);
}else{
textView = (TextView)convertView;
}
textView.setText(data.get(position));
return textView;
}
@Override
public Filter getFilter() {
Filter filter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
ArrayList newData = new ArrayList<>();
if(constraint != null && !constraint.toString().contains("@")){
for(String data : emails){
newData.add(constraint+data);
}
}
results.values = newData;
results.count = newData.size();
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
data = (ArrayList)results.values;
notifyDataSetChanged();
}
};
return filter;
}
}
到此为止,用AutoCompleteTextView与自定义Adapter实现一个简单的自动补全功能已经完成了。
注:本人还是新手,文中若有错误或者讲述不正当的地方,欢迎指出
一些参考文章:
Filterable与Filter
android Filter
Android数据过滤器:Filter