Populate and manipulate AutoCompleteTextView in Android

If you ever encounter AutoCompleteTextView in your Android project, you must have had the following questions in your mind.
– How to provide data for AutoCompleteTextView
– How to design row item for AutoCompleteTextView
– How to check which item selected in AutoCompleteTextView
– How to populate AutoCompleteTextView from an array of data class without implementing an adapter
– How to change search(filter) preferences
– etc…

In this tutorial, I will answer all your questions.

Here we use Kotlin language for creating this example.
First of all, we will create the layout for the AutoCompleteTextView.

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingBottom="@dimen/activity_vertical_margin"
  tools:context="com.acomputerengineer.AutoCompleteTextViewActivity">
  
  <com.google.android.material.textfield.TextInputLayout
    android:id="@+id/til"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent">

    <AutoCompleteTextView
      android:id="@+id/actv"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:hint="@string/your_hint_here"
      android:inputType="text"
      android:maxLines="1" />
  </com.google.android.material.textfield.TextInputLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

Now we will see 3 different cases for AutoCompleteTextView.

First Case
Here we use array of strings to populate AutoCompleteTextView and display list.

First, we will create the list of movies as a string array and display it in AutoCompleteTextView using the default ArrayAdapter.

val movies = arrayOf("Avengers: Endgame", "Captain Marvel", "Shazam!", "Spider-Man: Far From Home", "Dark Phoenix", "Hellboy", "Glass", "Reign of the Superman", "Brightburn")
val adapter1 = ArrayAdapter(this, android.R.layout.select_dialog_item, movies)

//actv is the AutoCompleteTextView from your layout file
actv.threshold = 1 //start searching for values after typing first character
actv.setAdapter(adapter1)

Here is the result:

AutoCompleteTextView in Android
AutoCompleteTextView in Android

Second Case
Here we use an array of a custom object of data class to populate AutoCompleteTextView and display list.
We will create the list of movies as a Movie data class array and display it in AutoCompleteTextView using the default ArrayAdapter. The ArrayAdapter uses “toString()” method of a data class if there is data class array provided.

So first we will create a data class named Movie.

data class Movie(
  val name: String,
  val year: Int
) {
  override fun toString(): String {
    return name.plus(" - ").plus(year)
  }
}

Now we will create the adapter and set it to the AutoCompleteTextView.

val movieObjects = arrayOf(Movie("Avengers: Endgame", 2019), Movie("Captain Marvel", 2019), Movie("Shazam!", 2019), Movie("Spider-Man: Far From Home", 2019), Movie("Dark Phoenix", 2019), Movie("Hellboy", 2019), Movie("Glass", 2019), Movie("Reign of the Superman", 2019), Movie("Brightburn", 2019))
val adapter2 = ArrayAdapter(this, android.R.layout.select_dialog_item, movieObjects)

//actv is the AutoCompleteTextView from your layout file
actv.threshold = 1 //start searching for values after typing first character
actv.setAdapter(adapter2)

Here is the result:

AutoCompleteTextView in Android
AutoCompleteTextView in Android

Now in both above case, you may have noticed that the design for the row is single text line provided in ‘android.R.layout.select_dialog_item’ layout. If we want to create a custom layout, we need to create a custom ArrayAdapter and inflate our layout there.

You may also have noticed that here when I type “ma”, it only displays one result “Captain Marvel” because the default filter uses “startsWith()” function so it only selects the result which has words start with “ma”. So to check in the whole string, we need to create a custom filter in the ArrayAdapter. So let’s see that.

Third Case
Here first we create an adapter that extends ArrayAdapter and in that we will inflate our custom layout and also add logic for our filter method.

class AutoCompleteTextViewAdapter(private val c: Context, @LayoutRes private val layoutResource: Int, private val movies: Array<AutoCompleteTextViewActivity.Movie>) :
  ArrayAdapter<AutoCompleteTextViewActivity.Movie>(c, layoutResource, movies) {

  var filteredMovies: List<AutoCompleteTextViewActivity.Movie> = listOf()

  override fun getCount(): Int = filteredMovies.size

  override fun getItem(position: Int): AutoCompleteTextViewActivity.Movie = filteredMovies[position]

  override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
    val view = convertView ?: LayoutInflater.from(c).inflate(layoutResource, parent, false)

    view.tvMovieName.text = filteredMovies[position].name
    view.tvMovieYear.text = filteredMovies[position].year.toString()

    return view
  }

  override fun getFilter(): Filter {
    return object : Filter() {
      override fun publishResults(charSequence: CharSequence?, filterResults: FilterResults) {
        @Suppress("UNCHECKED_CAST")
        filteredMovies = filterResults.values as List<AutoCompleteTextViewActivity.Movie>
        notifyDataSetChanged()
      }

      override fun performFiltering(charSequence: CharSequence?): FilterResults {
        val queryString = charSequence?.toString()?.toLowerCase()

        val filterResults = FilterResults()
        filterResults.values = if (queryString == null || queryString.isEmpty())
            movies.asList()
          else
            movies.filter {
              it.name.toLowerCase().contains(queryString) || it.year.toString().contains(queryString)
            }
        return filterResults
      }
    }
  }
}

Here is the layout for this adapter “item_auto_complete_text_view.xml”

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingBottom="@dimen/activity_vertical_margin">

  <TextView
    android:id="@+id/tvMovieName"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

  <TextView
    android:id="@+id/tvMovieYear"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginTop="5dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/tvMovieName" />

</androidx.constraintlayout.widget.ConstraintLayout>

Now we use this adapter.

val movieObjects = arrayOf(Movie("Avengers: Endgame", 2019), Movie("Captain Marvel", 2019), Movie("Shazam!", 2019), Movie("Spider-Man: Far From Home", 2019), Movie("Dark Phoenix", 2019), Movie("Hellboy", 2019), Movie("Glass", 2019), Movie("Reign of the Superman", 2019), Movie("Brightburn", 2019))
val adapter3 = AutoCompleteTextViewAdapter(this,  R.layout.item_auto_complete_text_view, movieObjects1)

//actv is the AutoCompleteTextView from your layout file
actv.threshold = 1 //start searching for values after typing first character
actv.setAdapter(adapter3)

See the result here:

AutoCompleteTextView in Android
AutoCompleteTextView in Android

Here you can see we have a custom layout where we have name and year below that. You also notice one thing that we now have all the result which contains string “ma” in the result. Because we use “contains()” function in our filter in the adapter.

Now we will see the listeners for AutoCompleteTextView which helps us to determine if the user selects any result from the suggestion or type any new text.

actv.setOnItemClickListener { adapterView, view, i, l ->
  val movie = adapterView.getItemAtPosition(i)
  //for adapter2 and adapter3
  if (movie is Movie) {
    Toast.makeText(this, "Selected item: ".plus(movie.name), Toast.LENGTH_LONG).show()
  }
  //for adapter1
  else if (movie is String) {
    Toast.makeText(this, "Selected item: ".plus(movie), Toast.LENGTH_LONG).show()
  }
}

Here you can check if the item is selected or not from the suggestions. You can also implement TextWatcher in the AutoCompleteTextView to check if the value is edited or not.

You can find the whole code in my github repo: https://github.com/dakshbhatt21/a-computer-engineer

Display List in AlertDialog in Android(Simple List, Radio Button List, Check Box List)

You don’t need to create custom view to display list in your AlertDialog. AlertDialog has the ability to display different kind of lists itself. Here we will see the 3 different types of methods to display the list in AlertDialog.

1. Simple List
Here we will display simple list in the AlertDialog. Here we need to provide the array of String to the AlertDialog and that’s it, it will handle the rest. We can also add Ok/Cancel button to the list but we won’t need it in the simple list.
We can use this list dialog in place of dropdown list(spinner).

First we declare the String array and then we create the AlertDialog.

String[] listItems = {"one", "two", "three", "four", "five"};

AlertDialog.Builder builder = new AlertDialog.Builder(ListAlertDialogActivity.this);
builder.setTitle("Choose item");

builder.setItems(listItems, new DialogInterface.OnClickListener() {
  @Override
  public void onClick(DialogInterface dialog, int which) {
    Toast.makeText(ListAlertDialogActivity.this, "Position: " + which + " Value: " + listItems[which], Toast.LENGTH_LONG).show();
  }
});

AlertDialog dialog = builder.create();
dialog.show();

The above code will display the list in the dialog like this.

Simple List in AlertDialog
Simple List in AlertDialog

2. Radio Button List
Now we will display list with Radio Button in the AlertDialog. You can use such list when you want to select only 1 item from the list of items. This is similar to the first one in the functionality but the visual representation is different. Here we will add positive button(OK/Done) to confirm the selection once the user select his/her option via Radio Button. Here we use the same String array as previous one.
We can use this list dialog in place of dropdown list(spinner).

String[] listItems = {"one", "two", "three", "four", "five"};

AlertDialog.Builder builder = new AlertDialog.Builder(ListAlertDialogActivity.this);
builder.setTitle("Choose item");

int checkedItem = 0; //this will checked the item when user open the dialog
builder.setSingleChoiceItems(listItems, checkedItem, new DialogInterface.OnClickListener() {
  @Override
  public void onClick(DialogInterface dialog, int which) {
    Toast.makeText(ListAlertDialogActivity.this, "Position: " + which + " Value: " + listItems[which], Toast.LENGTH_LONG).show();
  }
});

builder.setPositiveButton("Done", new DialogInterface.OnClickListener() {
  @Override
  public void onClick(DialogInterface dialog, int which) {
    dialog.dismiss();
  }
});

AlertDialog dialog = builder.create();
dialog.show();

The above code will display the list in the dialog with radio button like this.

Radio Button List in AlertDialog
Radio Button List in AlertDialog

3. Check Box List
This list is very important as we are going to select multiple items from the list using checkbox. We can use this list in many project where you want to select multiple items. Here we need to add confirmation button(OK/Done) after user selects all the items he/she wants. Here we use the same String array as previous one.
We can also call this a multi-select list or multi select dropdown list.

String[] listItems = {"one", "two", "three", "four", "five"};

AlertDialog.Builder builder = new AlertDialog.Builder(ListAlertDialogActivity.this);
builder.setTitle("Choose items");

boolean[] checkedItems = new boolean[]{true, false, true, false, true}; //this will checked the items when user open the dialog
builder.setMultiChoiceItems(listItems, checkedItems, new DialogInterface.OnMultiChoiceClickListener() {
  @Override
  public void onClick(DialogInterface dialog, int which, boolean isChecked) {
    Toast.makeText(ListAlertDialogActivity.this, "Position: " + which + " Value: " + listItems[which] + " State: " + (isChecked ? "checked" : "unchecked"), Toast.LENGTH_LONG).show();
  }
});

builder.setPositiveButton("Done", new DialogInterface.OnClickListener() {
  @Override
  public void onClick(DialogInterface dialog, int which) {
    dialog.dismiss();
  }
});

AlertDialog dialog = builder.create();
dialog.show();

The above code will display the list in the dialog with radio button like this.

Check Box List in AlertDialog
Check Box List in AlertDialog

You can find the source code for this on my github repo: https://github.com/dakshbhatt21/a-computer-engineer