Skip to content Skip to sidebar Skip to footer

How To Add A Custom Adapter To An Autocompletetextview

Is there any simple way to set a 2 TextView dropdown to an AutoCompleteTextView. There is android.R.layout.two_line_list_item Which I couldn't find any examples how to use. So, I t

Solution 1:

Here Code is working for me,

Set This adapter to autocompletetextview

AutoCompleteTextViewetProductSearch= (AutoCompleteTextView)getView().findViewById(R.id.edtSearchBoxTakeOrder);
ProductSearchAdapteradapter=newProductSearchAdapter(getActivity(), android.R.layout.simple_dropdown_item_1line, productList);
etProductSearch.setAdapter(adapter );

ProductSearchAdapter class

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

publicclassProductSearchAdapterextendsArrayAdapter<ProductDataModel> {
    private ArrayList<ProductDataModel> items;
    private ArrayList<ProductDataModel> itemsAll;
    private ArrayList<ProductDataModel> suggestions;
    privateint viewResourceId;

    @SuppressWarnings("unchecked")publicProductSearchAdapter(Context context, int viewResourceId,
            ArrayList<ProductDataModel> items) {
        super(context, viewResourceId, items);
        this.items = items;
        this.itemsAll = (ArrayList<ProductDataModel>) items.clone();
        this.suggestions = newArrayList<ProductDataModel>();
        this.viewResourceId = viewResourceId;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        Viewv= convertView;
        if (v == null) {
            LayoutInflatervi= (LayoutInflater) getContext().getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(viewResourceId, null);
        }
        ProductDataModelproduct= items.get(position);
        if (product != null) {
              TextViewproductLabel= (TextView)  v.findViewById(android.R.id.text1);
            if (productLabel != null) {
                productLabel.setText(product.getProductName());
            }
        }
        return v;
    }

    @Overridepublic Filter getFilter() {
        return nameFilter;
    }

    FilternameFilter=newFilter() {
        public String convertResultToString(Object resultValue) {
            Stringstr= ((ProductDataModel) (resultValue)).getProductName();
            return str;
        }

        @Overrideprotected FilterResults performFiltering(CharSequence constraint) {
            if (constraint != null) {
                suggestions.clear();
                for (ProductDataModel product : itemsAll) {
                    if (product.getProductName().toLowerCase()
                            .startsWith(constraint.toString().toLowerCase())) {
                        suggestions.add(product);
                    }
                }
                FilterResultsfilterResults=newFilterResults();
                filterResults.values = suggestions;
                filterResults.count = suggestions.size();
                return filterResults;
            } else {
                returnnewFilterResults();
            }
        }

        @OverrideprotectedvoidpublishResults(CharSequence constraint,
                FilterResults results) {
            @SuppressWarnings("unchecked")
            ArrayList<ProductDataModel> filteredList = (ArrayList<ProductDataModel>) results.values;
            if (results != null && results.count > 0) {
                clear();
                for (ProductDataModel c : filteredList) {
                    add(c);
                }
                notifyDataSetChanged();
            }
        }
    };

}

Solution 2:

According to the documentation, the inferred type of setAdapter in AutoCompleteTextView is :

<T extendsListAdapter & Filterable> voidsetAdapter(T adapter)

Your adapter must be a ListAdapter (which BaseAdapter is, so far so good) and a Filterable, which BaseAdapter is not, nor is your Adapter implementation. I would extend an ArrayAdapter, which is Filterable, not to mention is would simplify your implementation (some of your methods duplicate methods of ArrayAdapter for the same result) :

publicclassTwoLineDropdownAdapterextendsArrayAdapter<TwoLineDropDown> {

    privateLayoutInflatermInflater=null;
    private Activity activity;

    publicTwoLineDropdownAdapter(Activity a, ArrayList<TwoLineDropDown> items) {
        super(a, 0, items);
        activity = a;
        mInflater = (LayoutInflater) activity
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    publicstaticclassViewHolder {

        public TextView title;
        public TextView description;
    }

    public View getView(finalint position, View convertView, ViewGroup parent) {

        ViewHolder holder;

        if (convertView == null) {

            holder = newViewHolder();

            convertView = mInflater.inflate(R.layout.dropdown_text_twoline,
                    parent, false);
            holder.title = (TextView) convertView
                    .findViewById(R.id.text1);
            holder.description = (TextView) convertView
                    .findViewById(R.id.text2);

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

        return convertView;
    }
}

Solution 3:

Converted Dwivedi Ji's answer to Kotlin. I had some issue with Android Studio's auto convert. Thus, spent some time to make it work.

Now it is working. In case anyone needs it (in my case, I am filtering street names):

classStreetsAdapter( privateval mContext: Context,
                      privateval viewResourceId: Int,
                      privateval items: ArrayList<Street>) : ArrayAdapter<Street?>(mContext, viewResourceId, items.toList()) {

    privateval itemsAll = items.clone() as ArrayList<Street>
    privatevar suggestions = ArrayList<Street>()

    overridefungetView(position: Int, convertView: View?, parent: ViewGroup): View {
        var v: View? = convertView
        if (v == null) {
            val vi = mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
            v = vi.inflate(viewResourceId, null)
        }
        val street: Street? = items[position]
        if (street != null) {
            val streetTitle = v?.findViewById(R.id.tvStreetTitle) as TextView?
            streetTitle?.text = street.title
        }
        return v!!
    }

    overridefungetFilter(): Filter {
        return nameFilter
    }

    privatevar nameFilter: Filter = object : Filter() {
        overridefunconvertResultToString(resultValue: Any): String {
            return (resultValue as Street).title
        }

        overridefunperformFiltering(constraint: CharSequence?): FilterResults {
            returnif (constraint != null) {
                suggestions.clear()
                for (street in itemsAll) {
                    if (street.title.toLowerCase().startsWith(constraint.toString().toLowerCase())) {
                        suggestions.add(street)
                    }
                }
                val filterResults = FilterResults()
                filterResults.values = suggestions
                filterResults.count = suggestions.size
                filterResults
            } else {
                FilterResults()
            }
        }

        overridefunpublishResults(constraint: CharSequence?, results: FilterResults?) {
            val filteredList =  results?.values as ArrayList<Street>?

            if (results != null && results.count > 0) {
                clear()
                for (c: Street in filteredList ?: listOf<Street>()) {
                    add(c)
                }
                notifyDataSetChanged()
            }
        }
    }
}

And set your adapter:

val adapter = StreetsAdapter(this,
       R.layout.item_street, //Your layout. Make sure it has [TextView] with id "tvStreetTitle" 
       arrayListOf() //Your list goes here
)
autoTextView.threshold = 1//will start working from first character
autoTextView.setAdapter(adapter)

Solution 4:

I believe that the easiest approach is to extend SimpleAdapter.

publicclassMyAdapterextendsandroid.widget.SimpleAdapter {

    staticArrayList<Map<String, String>> toMapList(Collection<MyObject> objectsCollection) {
        ArrayList<Map<String, String>> objectsList = newArrayList<Map<String, String>>(objectsCollection.size());
        for (MyObject obj : objectsCollection) {
            Map<String, String> map = newHashMap<String, String>();
            map.put("name", obj.getName());
            map.put("details", obj.getDetails());
            objectsList.add(map);
        };
        return objectsList;
    }

    publicMyAdapter(Context context, Collection<MyObject> objects) {

        super(context, toMapList(objects),
              R.layout.auto_complete_layout, newString[] {"name", "description"}, new int[] {R.id.name, R.id.description});
    }
}

The major drawback is that this will bring candidates based on any space-delimited word in either name or description. If you add another field to your auto_complete_layout, it will be involved in matching, too.

Therefore, I finished with rewriting the SimpleAdapter to better fit my needs, removing a significant amount of the base class overhead which was not relevant for my use case. But the few lines above give you a good start, and provide a solid reference to start customization from.

Solution 5:

Always keep in mind that when you are customizing ArrayAdapter for your AutoCompleteTextView, you have to implement your own filtering method.

Post a Comment for "How To Add A Custom Adapter To An Autocompletetextview"