关于AutoCompeletTextView的Adapter写法

这两天公司做一个功能,

需要实现的就是在EditText中输入一个文本,然后根据输入的文本进行模糊查询,将结果放入到一个类似listview的列表中

最后通过点击列表中的条目,将数据展示到EditText中。


其实这个功能很久以前也有人讲过,此外针对这一功能google也有原生控件AutoCompeletTextView,

但是大部分的帖子用的也都是Google的ArrayAdapter。


如果是简简单单用单列字符串来实现,这个无可厚非,但是如果用到了复杂的item时,ArrayAdapter就表现的力不从心了。

因此自定义Adapter是十分必要的。


首先需要谢谢

Ricky大神的帖子,将我引领入门

也可以看一下原贴 http://blog.csdn.net/top_code/article/details/9326129

但是针对最后,整个项目中有一个小的bug


我所做的就是在前人的基础上做一下修改,以便为更多程序员带来一个更详细一点的使用方法

这里是主Activity

package com.autobyselfadapter;


import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AutoCompleteTextView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends Activity implements OnItemClickListener {
    List<PhoneContact> mList;
    private AutoCompleteTextView mACTV;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        buildAppData();
        findView();
    }

    private void buildAppData() {
        String[] names = { "abc", "allen", "bird", "bike", "book", "cray",
                "david", "demon", "eclipse", "felling", "frank", "google",
                "green", "hill", "hook","jin zhiwen", "jack", "jay", "king","kevin","kobe",
                "lily", "lucy", "mike", "nike", "nail", "open","open cv",
                "panda", "pp", "queue", "ray allen", "risk", "tim cook","T-MAC",
                "tony allen",
                "x man", "x phone", "yy", "world", "w3c", "zoom","zhu ziqing"};

        mList = new ArrayList<PhoneContact>();

        for (int i = 0; i < names.length; i++) {
            PhoneContact pc = new PhoneContact(100 + i, names[i], "1861234567"
                    + i, names[i].concat("@gmail.com"));
            mList.add(pc);
        }

    }

    private void findView() {
        mACTV = (AutoCompleteTextView) findViewById(R.id.mACTV);
        PhoneAdapter mAdapter = new PhoneAdapter(mList, getApplicationContext());
        mACTV.setAdapter(mAdapter);
        mACTV.setThreshold(1);  //设置输入一个字符 提示,默认为2

        mACTV.setOnItemClickListener(this);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
                            long id) {

//      honeContact pc = mList.get(position); 
	//这里是原贴代码,当然也是bug的问题所在
	//其取值是用原集合中获取的,因此不管我们搜索出结果展示的是什么,只要点击
	//控件只会从原集合中按照索引进行选择,因此会出现例如输入x 会提示 x abc , x man ,然后我们点击第一个x abc但是展示的却是abc的数据
        
	PhoneContact pc = ((PhoneAdapter)parent.getAdapter()).getFilteredList().get(position);
        mACTV.setText(pc.getName()+" "+pc.getPhone());
    }

}




这里是布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <AutoCompleteTextView
        android:id="@+id/mACTV"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="" >

        <requestFocus />
    </AutoCompleteTextView>

</RelativeLayout>
在原贴中没有bean类,因此,这里添上

package com.autobyselfadapter;

/**
 * Created by Administrator on 2016/11/20.
 */
public class PhoneContact {

    private int id;
    private String name;
    private String email;
    private String phone;

    public void setEmail(String email) {
        this.email = email;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public PhoneContact(int id, String name, String phone, String email) {
        this.id = id;
        this.name = name;
        this.phone = phone;
        this.email = email;
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }

    public String getPhone() {
        return phone;
    }
}


这里是关于item的布局

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <ImageView
        android:id="@+id/ivIcon"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:contentDescription="@string/app_name"
        android:src="@mipmap/ic_launcher" />

    <LinearLayout
        android:id="@+id/appInfo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dip"
        android:layout_toRightOf="@id/ivIcon"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="person_name"
            android:textColor="#000000"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/tv_phone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="phone"
            android:textColor="#666666"
            android:textSize="13sp" />

        <TextView
            android:id="@+id/tv_email"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="email"
            android:textColor="#666666"
            android:textSize="13sp" />
    </LinearLayout>

    <Button
        android:id="@+id/btnClick"
        android:layout_width="80dip"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:focusable="false"
        android:text="call"
        android:textColor="#000000"
        android:textSize="16sp" />

</RelativeLayout>

下面是重点,也就是adapter的部分,

是继承了BaseAdapter,但是如果是给AutoCompleteTextView做适配

还必须要实现一个Filterable接口

下面会着重注释一下Filter的代码

package com.autobyselfadapter;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;


public class PhoneAdapter extends BaseAdapter implements Filterable {
    //全局变量Filter
    private ArrayFilter mFilter;
    //全局变量初始化的数据集合
    private List<PhoneContact> mList;
    //上下文
    private Context context;
    //未进行过滤的数据集合
    private ArrayList<PhoneContact> mUnfilteredData;
    //已经进行过滤了的数据集合
    private ArrayList<PhoneContact> mfilteredData;

    public PhoneAdapter(List<PhoneContact> mList, Context context) {
        this.mList = mList;
        this.context = context;
    }

    @Override
    public int getCount() {

        return mList==null ? 0:mList.size();
    }

    @Override
    public Object getItem(int position) {
        return mList.get(position);
    }

    @Override
    public long getItemId(int position) {

        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view;
        ViewHolder holder;
        if(convertView==null){
            view = View.inflate(context, R.layout.phone_item, null);

            holder = new ViewHolder();
            holder.tv_name = (TextView) view.findViewById(R.id.tv_name);
            holder.tv_phone = (TextView) view.findViewById(R.id.tv_phone);
            holder.tv_email = (TextView) view.findViewById(R.id.tv_email);

            view.setTag(holder);
        }else{
            view = convertView;
            holder = (ViewHolder) view.getTag();
        }

        PhoneContact pc = mList.get(position);

        holder.tv_name.setText("姓名:"+pc.getName());
        holder.tv_phone.setText("电话:"+pc.getPhone());
        holder.tv_email.setText("Email:"+pc.getEmail());

        return view;
    }

    static class ViewHolder{
        public TextView tv_name;
        public TextView tv_phone;
        public TextView tv_email;
    }

    //getFilter方法就是实现了Filterable接口需要实现的方法
    //此处必须要有一个过滤器实例化的返回值
    @Override
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new ArrayFilter();
        }
        return mFilter;
    }

    public ArrayList<PhoneContact> getFilteredList()
    {
        return mfilteredData;

    }

    /**
     * 自定义Filter(过滤器必须实现的两个方法 performFiltering 还有 publishResults )
     */
    private class ArrayFilter extends Filter {
        /**
         * performFiltering 方法的作用是在子线程中运行,此外进行数据过滤
         * 将符合条件的数据装入一个新的集合(新集合的作用就是存放符合条件)
         * @param prefix 用户在控件中输入的字符
         * @return  过滤结果集, 此处的返回值在publishResults方法中作为参数传入
         */
        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            //初始化一个FilterResult
            FilterResults results = new FilterResults();
            //初始化未过滤集合,如果该集合未初始化,则进行初始化
            if (mUnfilteredData == null) {
                mUnfilteredData = new ArrayList<PhoneContact>(mList);
            }
            //对用户输入进行判断
            if (prefix == null || prefix.length() == 0) {
                //用户没有输入,数据不会产生变化
                ArrayList<PhoneContact> list = mUnfilteredData;
                results.values = list;
                results.count = list.size();
            } else {
                //如果用户输入,或者是控件内存在字符
                //将字符变为小写字符(后面叫做"查询字符串")
                String prefixString = prefix.toString().toLowerCase();
                //这一段总感觉没有用,不过支持原创,该句还是保留
                ArrayList<PhoneContact> unfilteredValues = mUnfilteredData;
                //获取总数据的长度(未过滤情况下,未过滤集合的长度就是总数据的长度)
                int count = unfilteredValues.size();
                //定义一个集合用户装过滤出来的数据(本人觉得这里的一句写的很好,直接定义出集合的大小
                // 因此,不会出现集合长度不够,重新申请.或者是集合长度太大,造成内存浪费)
                ArrayList<PhoneContact> newValues = new ArrayList<PhoneContact>(count);
                //进行对未过滤数据循环遍历
                for (int i = 0; i < count; i++) {
                    PhoneContact pc = unfilteredValues.get(i);
                    if (pc != null) {

                        if(pc.getName()!=null && pc.getName().startsWith(prefixString)){
                            /**进行判断如果用户名存在,并且用户名是用查询字符串开头,则符合条件*/
                            newValues.add(pc);
                        }else if(pc.getEmail()!=null && pc.getEmail().startsWith(prefixString)){
                            /**若上一条不符合,可以再用电子邮件进行判断,如果匹配,表示符合条件*/
                            newValues.add(pc);
                        }
                    }
                }
                //将过滤出来的数据传给全局变量过滤后数据
                mfilteredData = newValues;

                //对返回结果进行一个数据传递,分别是集合本身 还有集合长度
                results.values = newValues;
                results.count = newValues.size();
            }

            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint,
                                      FilterResults results) {
            //FilterResults 的 返回值作为参数传递到这里
            //可以通过results 获取到过滤后集合,然后传给作用于显示的集合
            mList = (List<PhoneContact>) results.values;
            //此外对集合元素数量进行判断
            if (results.count > 0) {
                //如果大于0,进行刷新,展示
                notifyDataSetChanged();
            } else {
                //如果为0 则还原初始状态并且不会显示出来
                notifyDataSetInvalidated();
            }
        }

    }
}


与其说本文着重写AutoCompleteTextView,其实最重要的还是强调了一下关于Filter的写法,希望可以帮助到各位.





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值