使用自定义适配器和过滤器的Autocompletetextview

14

我正在尝试为我的AutoCompleteTextView设置自定义的ArrayAdapter,就像这样:

public class AutoCompleteContactArrayAdapter extends
    ArrayAdapter<Map<String, String>> implements Filterable {
private Context mContext;
private List<Map<String, String>> mContactList;

public AutoCompleteContactArrayAdapter(Context context,
        List<Map<String, String>> objects) {
    super(context, R.layout.auto_contact_list, objects);
    mContext = context;
    mContactList = objects;
    // TODO Auto-generated constructor stub
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    LayoutInflater inflater = (LayoutInflater) mContext
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View rowView = inflater.inflate(R.layout.auto_contact_list, parent,
            false);
    TextView nameView = (TextView) rowView.findViewById(R.id.ccontName);
    TextView phoneView = (TextView) rowView.findViewById(R.id.ccontNo);
    TextView typeView = (TextView) rowView.findViewById(R.id.ccontType);
    Map<String, String> contactMap = mContactList.get(position);

    nameView.setText(contactMap.get("name"));
    phoneView.setText(contactMap.get("phone"));
    typeView.setText(contactMap.get("type"));

    return rowView;
}
@Override
public Filter getFilter() {
    return new Filter() {
        @Override
        protected void publishResults(CharSequence constraint,
                FilterResults results) {

            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            ArrayList<String> result = new ArrayList<String>();
            result.add("test");
            result.add("another");
            result.add("last");
            FilterResults r = new FilterResults();
            r.values = result;
            r.count = result.size();
            return r;
        }
    };
}
}
在调试中,应用程序进入了 publishResults()performFiltering() 方法,但显示的结果集不是我的测试 array [test,another,last],而只是显示所有结果,忽略了我的过滤器。
5个回答

39

这是我的代码的当前实现:

xml

<AutoCompleteTextView
    android:id="@+id/searchAutoComplete"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_centerVertical="true"
    android:layout_marginRight="10dp"
    android:layout_toRightOf="@+id/linearLayout1"
    android:background="@drawable/abs__textfield_search_default_holo_light"
    android:drawableLeft="@drawable/abs__ic_search_api_holo_light"
    android:drawableRight="@drawable/abs__ic_clear_holo_light"
    android:hint="@string/search"
    android:imeOptions="actionSearch"
    android:inputType="textAutoComplete|textAutoCorrect" >

适配器:

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

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

public class AutoCompleteAdapter extends ArrayAdapter<String> implements Filterable {

    private ArrayList<String> fullList;
    private ArrayList<String> mOriginalValues;
    private ArrayFilter mFilter;

    public AutoCompleteAdapter(Context context, int resource, int textViewResourceId, List<String> objects) {

        super(context, resource, textViewResourceId, objects);
        fullList = (ArrayList<String>) objects;
        mOriginalValues = new ArrayList<String>(fullList);

    }

    @Override
    public int getCount() {
        return fullList.size();
    }

    @Override
    public String getItem(int position) {
        return fullList.get(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return super.getView(position, convertView, parent);
    }

    @Override
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new ArrayFilter();
        }
        return mFilter;
    }


    private class ArrayFilter extends Filter {
        private Object lock;

        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            FilterResults results = new FilterResults();

            if (mOriginalValues == null) {
                synchronized (lock) {
                    mOriginalValues = new ArrayList<String>(fullList);
                }
            }

            if (prefix == null || prefix.length() == 0) {
                synchronized (lock) {
                    ArrayList<String> list = new ArrayList<String>(mOriginalValues);
                    results.values = list;
                    results.count = list.size();
                }
            } else {
                final String prefixString = prefix.toString().toLowerCase();

                ArrayList<String> values = mOriginalValues;
                int count = values.size();

                ArrayList<String> newValues = new ArrayList<String>(count);

                for (int i = 0; i < count; i++) {
                    String item = values.get(i);
                    if (item.toLowerCase().contains(prefixString)) {
                        newValues.add(item);
                    }

                }

                results.values = newValues;
                results.count = newValues.size();
            }

            return results;
        }

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {

        if(results.values!=null){
        fullList = (ArrayList<String>) results.values;
        }else{
            fullList = new ArrayList<String>();
        }
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }
    }
}

最后,在代码中像这样初始化...

       ArrayList<String> searchArrayList= new ArrayList<String>();
//initilaze this array with your data
        AutoCompleteAdapter adapter = new AutoCompleteAdapter(this, android.R.layout.simple_dropdown_item_1line, android.R.id.text1, searchArrayList);
        autoCompleteTextView = (AutoCompleteTextView) customNav.findViewById(R.id.searchAutoComplete);
        autoCompleteTextView.setAdapter(adapter);

完成了 :)


嗨,我几乎都明白了,除了 mOriginalValues。我不明白我们为什么需要它。你能给我解释一下吗? - Ray
这不是优化过的代码,你可以根据自己的需要进行更改 :) - Ali Imran
非常好的解决方案。谢谢你的分享。你救了我的一天。非常感谢你 ;) - Simon Dorociak
是的,超级好的解决方案,它百分百有效 :) 非常感谢Ali Imran - Agilanbu
1
为什么你只在清空列表时使用synchronized (lock),而不是在分配新值时也使用呢?@AliImran - Sp4Rx

6

好的,我想我理解了Luksprog所说的,现在这段代码可以工作了,关键在于

mContactList = (ArrayList<Map<String, String>>) results.values;

@Override
public int getCount(){
    return mContactList.size();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    LayoutInflater inflater = (LayoutInflater) mContext
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View rowView = inflater.inflate(R.layout.auto_contact_list, parent,
            false);
    TextView nameView = (TextView) rowView.findViewById(R.id.ccontName);
    TextView phoneView = (TextView) rowView.findViewById(R.id.ccontNo);
    TextView typeView = (TextView) rowView.findViewById(R.id.ccontType);
    Map<String, String> contactMap = mContactList.get(position);

    nameView.setText(contactMap.get("name"));
    phoneView.setText(contactMap.get("phone"));
    typeView.setText(contactMap.get("type"));

    return rowView;
}
@Override
public Filter getFilter() {
    return new Filter() {
        @Override
        protected void publishResults(CharSequence constraint,
                FilterResults results) {

            if (results.count > 0) {
                mContactList = (ArrayList<Map<String, String>>) results.values;
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            ArrayList<Map<String, String>> result = new ArrayList<Map<String, String>>();
            HashMap<String,String> myMap = new HashMap<String,String>();
            myMap.put("name", "key");
            result.add(myMap);
            HashMap<String,String> myMap2 = new HashMap<String,String>();
            myMap2.put("name", "is");
            result.add(myMap2);
            HashMap<String,String> myMap3 = new HashMap<String,String>();
            myMap3.put("name", "another");
            result.add(myMap3);
            FilterResults r = new FilterResults();
            r.values = result;
            r.count = result.size();
            return r;
        }
    };
}

2

对于对Kotlin版本感兴趣的人,您可以在下面找到相关内容。

val ac = findViewById<AutoCompleteTextView>(R.id.searchAutoComplete)
var dataList = listOf("argument", "aid", "appear", "air", "advertise", "appendix", "apathy", "absence", "analysis",
    "bind", "bathroom", "broadcast", "bomb", "build", "bark", "beef", "brain", "bend",
    "conviction", "coincide", "castle", "cafe", "chemistry", "clean", "closed", "composer", "care", "crude")
ac.setAdapter(object : ArrayAdapter<String>(
    context, android.R.layout.simple_dropdown_item_1line, android.R.id.text1, dataList,
), Filterable {
    private var oriValue = dataList.toList()
    override fun getCount() = dataList.size
    override fun getItem(position: Int) = dataList[position]
    override fun getFilter() = object : Filter() {
        override fun performFiltering(prefix: CharSequence?) =
            FilterResults().apply {
                mutableListOf<String>().apply {
                    if (prefix == null || prefix.isEmpty()) addAll(oriValue)
                    else oriValue.map {
                        if (it.contains(prefix.toString(), true)) // ignore case
                        // if (it.contains(prefix.toString())) // match case
                        // if (it.startsWith(prefix.toString(), true)) // start with
                            add(it)
                    }
                    values = this
                    count = this.size
                }
            }
        override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
            @Suppress("UNCHECKED_CAST")
            dataList = results?.values as List<String>? ?: listOf()
            if (results?.count ?: -1 > 0) notifyDataSetChanged() 
            else notifyDataSetInvalidated()
        }
    }
})

2
Autocompletetextview使用Adapter来显示自动完成建议下拉框。
Adapater应该是可过滤的,并且应该为每个项目从数据列表中提供视图填充数据。 Autocompletetextview使用在适配器中定义的过滤器来获取结果并显示它们。
因此,如果您需要创建自定义适配器,则需要为getView提供实现并提供一个过滤器类。
完整的工作示例autocompletetextview自定义布局和自定义适配器。

http://www.zoftino.com/android-autocompletetextview-custom-layout-and-adapter


1

如果你想添加数据,那么以下代码是错误的:

String[] arr=new String[100];

你可以使用ArrayList来完成相同的工作,但请记住不要在其中放置Getter/Setter类。只需要简单地声明即可,例如:

在主分区中声明:

   ArrayList<String>arr=new ArrayList<>();

然后以这种方式进行初始化:
for (int i = 0; i < jsonArray.length(); i++) {
                JSONObject jsonObject1 = (JSONObject) jsonArray.get(i);
                String imei = jsonObject1.getString("imei");
                String name = jsonObject1.getString("name");
                String my_pic = jsonObject1.getString("my_pic");
                String email = jsonObject1.getString("email");

                arr.add(name);
            }


            adapter= new ArrayAdapter<>
                    (this, android.R.layout.select_dialog_item, arr);
            autoCompleteText.setThreshold(1);//will start working from first character
            autoCompleteText.setAdapter(adapter);//setting the adapter data into the AutoCompleteTextView
            autoCompleteText.setTextColor(Color.RED);


        }

我希望这对你有用。祝你好运。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接