AutocompleteTextView

header

Según la documentación de Google sobre Material Design.

Utiliza el campo de texto autocompletado para presentar sugerencias o terminaciones en un menú desplegable, de esta forma los usuarios pueden introducir información de forma más precisa y eficiente.

¿Cómo se añade?

I. Declara tu AutoCompleteTextView en cualquier layout.xml.

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

II. Crea una lista

II. Crea un string-array que contenga todas las sugerencias de texto en un fichero dentro del directorio res/values.

<?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 un filterable list adapter que maneje la lista de datos para el auto-completado.

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);  

¿Cómo modificar el estilo?

style

I. Declara tu estilo personalizado en el fichero styles.xml.

 <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. Aplica este estilo a tu AutoCompleteTextView mediante el atributo android:theme.

<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

Por defecto, el menú desplegable con la lista de datos filtrados aparece anclado justo debajo del AutoCompleteTextView.

Es posible cambiar esta posición utilizando el atributo dropDownAnchor para referenciar otro 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"
    />

Adapter Personalizado

style

Para personalizar completamente la apariencia del menú desplegable es necesario proporcionar tu propio Adapter, el cual tendrá que implementar las interfaces Filterable y ListAdapter.

La forma más fácil de conseguir esto es extendiendo ArrayAdapter que ya implementa ambas interfaces.

I. Crea un adapter propio extendiendo la clase ArrayAdapter.

class AutoCompleteDogsAdapter extends ArrayAdapter<Dog> {}  

II. Crea un filtro propio extendiendo la clase Filter y define tu propia lógica de filtrado sobreescribiendo el método performFiltering.

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();

            // Tu lógica de filtrado va aquí
            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. Proporciona tu filtro personalizado desde el nuevo adapter sobreescribiendo el método getFilter()

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;
    }