Android:自动补全文本框autoCompleteTextView

自动补全文本框在app中十分常见,我们平时接触到的搜索框都是autoCompleteTextView,当我们输入关键字的时候,就会出现一个下拉列表,方便我们快速查找需要的内容或提示我们进一步输入。

Android:自动补全文本框autoCompleteTextView

比如上图这样的就是一个自动补全文本框,但是这样的文本框有很多问题:1、不够美观。2、只能匹配开头相同的字符串。这些都是因为我用的是ArrayAdapter的原因,这样的自动补全文本框肯定不能满足应用的需求。于是我又做了一个自定义的适配器来解决这两个问题。

 Android:自动补全文本框autoCompleteTextView

比如上图这样的,类似ListView可以做成图文混排的样子。

1、需要JavaBean存放数据

Android:自动补全文本框autoCompleteTextView
 1 public class MyBean {
 2     private  int imageID;
 3     private String userName;
 4 
 5     public MyBean(int imageID, String userName) {
 6         this.imageID = imageID;
 7         this.userName = userName;
 8     }
 9 
10     public int getImageID() {
11         return imageID;
12     }
13 
14     public void setImageID(int imageID) {
15         this.imageID = imageID;
16     }
17 
18     public String getUserName() {
19         return userName;
20     }
21 
22     public void setUserName(String userName) {
23         this.userName = userName;
24     }
25 }
MyBean.java

 2、AutoCompleteTextView所在的布局文件(app/res/layout/activity_main.xml)

  AutoCompleteTextView的相关属性:(更多属性可参考:菜鸟教程的AutoCompleteTextView的基本使用

  • android:completionHint:设置下拉菜单中的提示标题
  • android:completionHintView:设置下拉菜单中提示标题的视图
  • android:completionThreshold:指定用户至少输入多少个字符才会显示提示
Android:自动补全文本框autoCompleteTextView
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:app="http://schemas.android.com/apk/res-auto"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     android:orientation="vertical"
 8     tools:context=".MainActivity">
 9 
10     <LinearLayout
11         android:layout_width="match_parent"
12         android:layout_height="wrap_content"
13         android:layout_marginTop="80dp"
14         android:orientation="horizontal">
15 
16         <TextView
17             android:id="@+id/t1"
18             android:layout_width="0dp"
19             android:layout_height="wrap_content"
20             android:layout_weight="1"
21             android:text="ArrayAdapter:" />
22 
23         <AutoCompleteTextView
24             android:id="@+id/actv1"
25             android:layout_width="0dp"
26             android:layout_height="wrap_content"
27             android:layout_weight="2" />
28     </LinearLayout>
29 
30     <LinearLayout
31         android:layout_width="match_parent"
32         android:layout_height="wrap_content"
33         android:layout_marginTop="80dp"
34         android:orientation="horizontal">
35 
36         <TextView
37             android:id="@+id/t2"
38             android:layout_width="0dp"
39             android:layout_height="wrap_content"
40             android:layout_weight="1"
41             android:text="自定义适配器:" />
42 
43         <AutoCompleteTextView
44             android:id="@+id/actv2"
45             android:background="@drawable/actv_bg"
46             android:completionHint="选择联系人"
47             android:completionHintView="@layout/actv_title"
48             android:layout_width="0dp"
49             android:layout_height="wrap_content"
50             android:layout_weight="2"
51             android:completionThreshold="1" />
52 
53     </LinearLayout>
54 
55 </LinearLayout>
activity_main.xml

3、自动补全文本框的背景(app/res/drawable/actv_bg.xml)

Android:自动补全文本框autoCompleteTextView
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <shape xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:shape="rectangle">
 4     <solid android:color="#ffffff"/><!--填充色-->
 5     <corners android:radius="30dp"/><!--圆角弧度-->
 6     <padding
 7         android:bottom="10dp"
 8         android:left="10dp"
 9         android:right="10dp"
10         android:top="10dp"/><!--内容与边框的间距-->
11     <stroke
12         android:color="#DCB879"
13         android:width="1dp"/><!--描边的粗细和颜色-->
14     <gradient
15         android:startColor="#ffffff"
16         android:endColor="#ffffff"
17         android:type="linear"
18         android:angle="360"/><!--渐变[渐变>填充]-->
19 </shape>
actv_bg.xml

4、设计每一项的样式布局(app/res/layout/actv_item.xml)

Android:自动补全文本框autoCompleteTextView
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:app="http://schemas.android.com/apk/res-auto"
 4     android:layout_width="match_parent"
 5     android:layout_height="wrap_content">
 6     <ImageView
 7         android:id="@+id/imageView"
 8         android:layout_width="50dp"
 9         android:layout_height="50dp"
10         android:layout_gravity="right"
11         app:srcCompat="@mipmap/ic_launcher" />
12     <TextView
13         android:id="@+id/tv_userName"
14         android:layout_width="0dp"
15         android:layout_height="match_parent"
16         android:layout_weight="1"
17         android:paddingLeft="30dp"
18         android:gravity="center_vertical"
19         android:text="TextView" />
20 </LinearLayout>
actv_item.xml

 5、设置下拉菜单中提示标题的视图的布局文件(app/res/layout/actv_title.xml)

  • TextView的id必须为 android:id="@android:id/text1"       
Android:自动补全文本框autoCompleteTextView
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="wrap_content">
 5 
 6     <TextView
 7         android:id="@android:id/text1"
 8         android:layout_width="match_parent"
 9         android:layout_height="wrap_content"
10         android:padding="2dp"
11         android:textColor="#cfcfcf"
12         android:textSize="10sp"
13         android:gravity="end"
14         />
15 </LinearLayout>
actv_title.xml

 6、定义适配器(MyAdapter.java)

  • 仿照ListView的做法,要修改下拉菜单的样式,就重写适配器的getView方法
  • 特别的是还需要适配器实现接口Filterable,并重写getFilter(),可以参考ArrayAdapter的源码实现,因为源码里用了a.startsWith(b),只能筛选开头相同的字符串,所以我改用a.contains(b),只要包含用户输入关键字就加入筛选后的列表。
  • 附上:ArrayAdapter的部分源码
    Android:自动补全文本框autoCompleteTextView
     1     @Override
     2     public @NonNull Filter getFilter() {
     3         if (mFilter == null) {
     4             mFilter = new ArrayFilter();
     5         }
     6         return mFilter;
     7     }
     8 
     9     /**
    10      * <p>An array filter constrains the content of the array adapter with
    11      * a prefix. Each item that does not start with the supplied prefix
    12      * is removed from the list.</p>
    13      */
    14     private class ArrayFilter extends Filter {
    15         @Override
    16         protected FilterResults performFiltering(CharSequence prefix) {
    17             final FilterResults results = new FilterResults();
    18 
    19             if (mOriginalValues == null) {
    20                 synchronized (mLock) {
    21                     mOriginalValues = new ArrayList<>(mObjects);
    22                 }
    23             }
    24 
    25             if (prefix == null || prefix.length() == 0) {
    26                 final ArrayList<T> list;
    27                 synchronized (mLock) {
    28                     list = new ArrayList<>(mOriginalValues);
    29                 }
    30                 results.values = list;
    31                 results.count = list.size();
    32             } else {
    33                 final String prefixString = prefix.toString().toLowerCase();
    34 
    35                 final ArrayList<T> values;
    36                 synchronized (mLock) {
    37                     values = new ArrayList<>(mOriginalValues);
    38                 }
    39 
    40                 final int count = values.size();
    41                 final ArrayList<T> newValues = new ArrayList<>();
    42 
    43                 for (int i = 0; i < count; i++) {
    44                     final T value = values.get(i);
    45                     final String valueText = value.toString().toLowerCase();
    46 
    47                     // First match against the whole, non-splitted value
    48                     if (valueText.startsWith(prefixString)) {
    49                         newValues.add(value);
    50                     } else {
    51                         final String[] words = valueText.split(" ");
    52                         for (String word : words) {
    53                             if (word.startsWith(prefixString)) {
    54                                 newValues.add(value);
    55                                 break;
    56                             }
    57                         }
    58                     }
    59                 }
    60 
    61                 results.values = newValues;
    62                 results.count = newValues.size();
    63             }
    64 
    65             return results;
    66         }
    ArrayAdapter.java
Android:自动补全文本框autoCompleteTextView
  1 public class MyAdapter extends BaseAdapter implements Filterable {
  2     private Context mcontext;
  3     private  List<MyBean> mFilteredList;//过滤后的列表
  4     private final List<MyBean> all_List;//需要过滤的列表
  5     private  ArrayFilter mFilter;
  6 
  7     public MyAdapter(Context mcontext, List<MyBean> all_List) {
  8         this.mcontext = mcontext;
  9         this.all_List =all_List;
 10         mFilteredList = all_List;
 11 
 12     }
 13 
 14     public List<MyBean> getmFilteredList() {
 15         return mFilteredList;
 16     }
 17 
 18     @Override
 19     public int getCount() {
 20         return mFilteredList.size();
 21     }
 22 
 23     @Override
 24     public Object getItem(int position) {
 25         return mFilteredList.get(position);
 26     }
 27 
 28     @Override
 29     public long getItemId(int position) {
 30         return position;
 31     }
 32 
 33     public class ViewHolder{
 34         ImageView imageID;
 35         TextView tv_userName;
 36     }
 37 
 38     @Override
 39     public View getView(int position, View convertView, ViewGroup parent) {
 40         ViewHolder holder;
 41         if(convertView==null){
 42             convertView=View.inflate(mcontext,R.layout.actv_item,null);
 43             holder=new ViewHolder();
 44             holder.tv_userName=convertView.findViewById(R.id.tv_userName);
 45             holder.imageID=convertView.findViewById(R.id.imageView);
 46             convertView.setTag(holder);
 47         }else{
 48             holder=(ViewHolder)convertView.getTag();
 49         }
 50         holder.tv_userName.setText(mFilteredList.get(position).getUserName());
 51         holder.imageID.setImageResource(mFilteredList.get(position).getImageID());
 52         return convertView;
 53     }
 54 
 55     @Override
 56     public Filter getFilter() {
 57         if (mFilter == null) {
 58             mFilter = new ArrayFilter();
 59         }
 60         return mFilter;
 61     }
 62     
 63     private class ArrayFilter extends Filter {
 64         @Override
 65         protected FilterResults performFiltering(CharSequence constraint) {//constraint是用户的输入
 66             //进行过滤的操作
 67             FilterResults results = new FilterResults();
 68 
 69             if (constraint == null || constraint.length() == 0) {
 70                 ArrayList<MyBean> list = new ArrayList<>(all_List);
 71                 results.values = list;
 72                 results.count = list.size();
 73             } else {
 74                 String prefixString = constraint.toString().toLowerCase();//大写换成小写
 75                 ArrayList<MyBean> values =new ArrayList<>(all_List);//未过滤前的List
 76                 int count = values.size();
 77                 ArrayList<MyBean> newValues = new ArrayList<>();//被过滤后的匹配的List
 78                 /*以下为过滤的条件,可按照个人的需求修改*/
 79                 for (int i = 0; i < count; i++) {
 80                     MyBean value = values.get(i);
 81                     String valueText = value.getUserName();//ValueText是每一项筛选的依据
 82 
 83                     if (valueText != null && valueText.startsWith(prefixString)) {
 84                         newValues.add(value);
 85                     } else {
 86                         if(valueText.contains(prefixString)) {
 87                             newValues.add(value);
 88                         }
 89                     }
 90                 }
 91                 results.values = newValues;
 92                 results.count = newValues.size();
 93             }
 94             return results;
 95         }
 96 
 97         @Override
 98         protected void publishResults(CharSequence constraint, FilterResults results) {
 99             //发表过滤的结果
100             mFilteredList = (List<MyBean>) results.values;
101             if (results.count > 0) {
102                 notifyDataSetChanged();
103             } else {
104                 notifyDataSetInvalidated();
105             }
106         }
107     }
108 }
MyAdapter.java

 7、在app/res/values/strings.xml存放用到的字符串和图片ID

Android:自动补全文本框autoCompleteTextView
 1 <resources>
 2     <string name="app_name">test</string>
 3     <string-array name="NameList">
 4         <item>张三</item>
 5         <item>李四</item>
 6         <item>王五</item>
 7         <item>张李</item>
 8         <item>李六</item>
 9         <item>陈八</item>
10         <item>杨七</item>
11         <item>常九</item>
12     </string-array>
13     <integer-array name="imageID">
14         <item>@drawable/images_01</item>
15         <item>@drawable/images_02</item>
16         <item>@drawable/images_03</item>
17         <item>@drawable/images_04</item>
18         <item>@drawable/images_05</item>
19         <item>@drawable/images_06</item>
20         <item>@drawable/images_07</item>
21         <item>@drawable/images_08</item>
22     </integer-array>
23 </resources>
strings.xml

 8、在MainActivity里为AutoCompleteTextView添加setOnItemClickListener的点击事件。

Android:自动补全文本框autoCompleteTextView
 1 public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
 2     MyAdapter adapter2;
 3     List<MyBean> userList;
 4     AutoCompleteTextView auto_tv2;
 5     @Override
 6     protected void onCreate(Bundle savedInstanceState) {
 7         super.onCreate(savedInstanceState);
 8         setContentView(R.layout.activity_main);
 9         //ArrayAdapter的自动补全文本框
10         String[] countries={"辽宁-沈阳","辽宁-大连","辽宁-鞍山","辽宁-营口","辽宁-盘锦",
11                 "辽宁-锦州","辽宁-抚顺","辽宁-本溪","辽宁-丹东","辽宁-朝阳","辽宁-辽阳","辽宁葫芦岛","辽宁-铁岭","辽宁-阜新"};
12         AutoCompleteTextView auto_tv1=findViewById(R.id.actv1);
13         ArrayAdapter adapter1=new ArrayAdapter(getApplicationContext(),android.R.layout.simple_list_item_1,countries);
14         auto_tv1.setAdapter(adapter1);
15         //自定义适配器的自动补全文本框
16         auto_tv2 =findViewById(R.id.actv2);
17         userList=init();//初始化数据
18         adapter2 =new MyAdapter(getApplicationContext(),userList);
19         auto_tv2.setAdapter(adapter2);
20         auto_tv2.setOnItemClickListener(this);
21     }
22 
23     protected List<MyBean> init(){//初始化数据
24         List<MyBean> list=new ArrayList<>();
25         String[] userName=getResources().getStringArray(R.array.NameList);
26         TypedArray typedArray =getResources().obtainTypedArray(R.array.imageID);
27         int[] imageID=new int[typedArray.length()];
28         for(int i=0;i< typedArray.length();i++){
29             imageID[i]=typedArray.getResourceId(i,0);
30         }
31         typedArray.recycle();
32         for(int i=0;i<imageID.length;i++){
33             list.add(new MyBean(imageID[i],userName[i]));
34         }
35         return list;
36     }
37 
38     @Override
39     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
40         /*使用自定义的Adapter后,需要修改点击后的事件,重新设置监听器
41         * *具体的响应事件可根据需求修改
42          */
43         MyBean data= adapter2.getmFilteredList().get(position);//data为筛选后的被点击的项
44         auto_tv2.setText(data.getUserName());
45     }
46 }
MainActivity.java

 

本文参考:AutoCompleteTextView的简单使用

Android:自动补全文本框autoCompleteTextView

上一篇:移动并重名文件,删除文件


下一篇:一张图明白Activity和Fragment对应的生命周期