Skip to content

Auto-complete

header

From Google Material Design documentation.

Use auto-complete text fields to present real-time suggestions or completions in dropdowns, so users can enter information more accurately and efficiently.

How to add?

I. Declare your AutoCompleteTextView inside any layout.xml.

<AutoCompleteTextView
    android:id="@+id/autocompleteView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="Search dogs..."/>

II. Define a string-array that contains all text suggestions in a file inside res/values directory.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="dogs_list">
        <item>Bichon Frise</item>
        <item>Border Collie</item>
        <item>Border Terrier</item>
        <item>Boxer</item>
        <item>Chihuahua</item>
        <item>German Shepherd</item>
        <item>Golden Retriever</item>
        <item>Greyhound</item>
    </string-array>
</resources>

III. Define a filterable list adapter to manage the auto completion data list.

int layoutItemId = android.R.layout.simple_dropdown_item_1line;
String[] dogArr = getResources().getStringArray(R.array.dogs_list);
List<String> dogList = Arrays.asList(dogsArr);
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, layoutItemId, dogList);

AutoCompleteTextView autocompleteView =
    (AutoCompleteTextView) findViewById(R.id.autocompleteView);
autocompleteView.setAdapter(adapter);

How to style?

style

I. Declare custom styles in your styles.xml file.

 <style name="Autocomplete" parent="Widget.AppCompat.Light.AutoCompleteTextView">
    <item name="android:background">@color/green500</item>
    <item name="colorControlNormal">@color/amber500</item>
    <item name="colorControlActivated">@color/cyan500</item>
</style>

II. Apply this style to the AutoCompleteTextView via android:theme attribute.

<AutoCompleteTextView
    android:id="@+id/autocomplete_dogs"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/Autocomplete"
    android:hint="Search dogs..." />

style

By default, the dropdown list with your filtered data appear just below the AutoCompleteTextView.

To change this position use dropDownAnchor attribute and reference another view id.

<AutoCompleteTextView
    android:id="@+id/autocomplete_dogs"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/Autocomplete"
    android:hint="Search dogs..."
    android:dropDownAnchor="@+id/header"
    android:dropDownWidth="match_parent"
    />

Custom Adapter

style

To fully customize the dropdown list you need to provide your own Adapter. It needs to implement Filterable and ListAdapter interfaces.

The easiest way to achieve this is by extending ArrayAdapter which already implements both interfaces.

I. Create a custom adapter extending ArrayAdapter class.

class AutoCompleteDogsAdapter extends ArrayAdapter<Dog> {
  ...
}

II. Create a custom filter extending Filter class and provide your own filtering logic overriding performFiltering method.

class DogsFilter extends Filter {

    AutoCompleteDogsAdapter adapter;
    List<Dog> originalList;
    List<Dog> filteredList;

    public DogsFilter(AutoCompleteDogsAdapter adapter, List<Dog> originalList) {
        super();
        this.adapter = adapter;
        this.originalList = originalList;
        this.filteredList = new ArrayList<>();
    }

    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        filteredList.clear();
        final FilterResults results = new FilterResults();

        if (constraint == null || constraint.length() == 0) {
            filteredList.addAll(originalList);
        } else {
            final String filterPattern = constraint.toString().toLowerCase().trim();

                  // Your filtering logic goes in here
            for (final Dog dog : originalList) {
                if (dog.breed.toLowerCase().contains(filterPattern)) {
                    filteredList.add(dog);
                }
            }
        }
        results.values = filteredList;
        results.count = filteredList.size();
        return results;
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        adapter.filteredDogs.clear();
        adapter.filteredDogs.addAll((List) results.values);
        adapter.notifyDataSetChanged();
    }
}

III. Provide your custom filter from your adapter class by overriding getFilter() method.

class AutoCompleteDogsAdapter extends ArrayAdapter<Dog> {

    private final List<Dog> dogs;
    private List<Dog> filteredDogs = new ArrayList<>();

    public AutoCompleteDogsAdapter(Context context, List<Dog> dogs) {
        super(context, 0, dogs);
        this.dogs = dogs;
    }

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

    @Override
    public Filter getFilter() {
        return new DogsFilter(this, dogs);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // Get the data item from filtered list.
        Dog dog = filteredDogs.get(position);

        // Inflate your custom row layout as usual.
        LayoutInflater inflater = LayoutInflater.from(getContext());
        convertView = inflater.inflate(R.layout.row_dog, parent, false);

        TextView tvName = (TextView) convertView.findViewById(R.id.row_breed);
        ImageView ivIcon = (ImageView) convertView.findViewById(R.id.row_icon);
        tvName.setText(dog.breed);
        ivIcon.setImageResource(dog.drawable);

        return convertView;
    }