Tolga Erbaş
3 min readOct 16, 2021

Android Kotlin MVVM Custom Array Adapter for AutoCompleteTextView

Android Jetpack is taken from official docs.

Sometimes we need custom array adapters for autoCompleteTextViews with the data that is fetched from API. For example, we have a CityApi which holds cities in our country. When a user enters two letters, it automatically completes to a referred city. Here is the code of the view in XML.

<com.google.android.material.textfield.MaterialAutoCompleteTextView
android:id="@+id/cityAutoCompleteView"
android:layout_width="match_parent"
android:layout_height="55dp"
android:paddingStart="16dp"
android:hint="@string/city"
android:imeOptions="actionNext"
android:singleLine="true"
android:completionThreshold="2"/>
MaterialAutoCompleteTextView

Then we create a data class of our object that we will store the data instances. If you have a data class for the API already, you can use it. I just wrote the data class for the dummy usage.

data class Cities(
val definition: String,
val id: String
)

Also, you can customize your autoCompleteViewItem. Just open a layout with the name autoCompleteTextViewItem and create a textView like this in the default layout.

<TextView
android:id="@+id/autoCompleteTextView"
android:layout_width="match_parent"
android:layout_height="?attr/dropdownListPreferredItemHeight"
android:ellipsize="middle"
android:paddingStart="16dp"
tools:text="@string/city" />

Also, you can use Android’s default item which can be used like this.

R.layout.support_simple_spinner_dropdown_item

Then we can write our Custom Array Adapter.

class CityAdapter(
private val mContext: Context,
private val mLayoutResourceId: Int,
cities: List<Cities>
) :
ArrayAdapter<Cities>(mContext, mLayoutResourceId, cities) {
private val city: MutableList<Cities> = ArrayList(cities)
private var allCities: List<Cities> = ArrayList(cities)

override fun getCount(): Int {
return city.size
}
override fun getItem(position: Int): Cities {
return city[position]
}
override fun getItemId(position: Int): Long {
return city[position].id.toLong()
}

override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var convertView = convertView
if (convertView == null) {
val inflater = (mContext as Activity).layoutInflater
convertView = inflater.inflate(mLayoutResourceId, parent, false)
}
try {
val city: Cities = getItem(position)
val cityAutoCompleteView = convertView!!.findViewById<View>(R.id.autoCompleteTextViewItem) as TextView
cityAutoCompleteView.text = city.definition
} catch (e: Exception) {
e.printStackTrace()
}
return convertView!!
}
}

Also you can use filtering.

override fun getFilter(): Filter {
return object : Filter() {
override fun convertResultToString(resultValue: Any) :String {
return (resultValue as Cities).definition
}
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filterResults = FilterResults()
if (constraint != null) {
val citySuggestion: MutableList<Cities> = ArrayList()
for (city in allCities) {
if (city.definition.toLowerCase() .startsWith(constraint.toString().toLowerCase())
) {
citySuggestion.add(city)
}
}
filterResults.values = citySuggestion
filterResults.count = citySuggestion.size
}
return filterResults
}
override fun publishResults(
constraint: CharSequence?,
results: FilterResults
) {
city.clear()
if (results.count > 0) {
for (result in results.values as List<*>) {
if (result is Cities) {
city.add(result)
}
}
notifyDataSetChanged()
} else if (constraint == null) {
city.addAll(allCities)
notifyDataSetInvalidated()
}
}
}
}
}

We wrote the Custom Array Adapter. Let's instantiate it in the fragment.

In the onCreateView(), after you bind your view with data binding,

you can instantiate it like this.

context?.let { ctx ->
val cityAdapter =
CityAdapter(ctx, R.layout.autoCompleteTextViewItem, cityList)
citySpinner.setAdapter(cityAdapter)
citySpinner.setOnItemClickListener { parent, _, position, _ ->
val city = cityAdapter.getItem(position) as Cities?
citySpinner.setText(city?.definition)
}

cityList is dummy data.

val cityList = mutableListOf(
Cities("London", "1"),
Cities("Miami", "2"),
Cities("California", "3"),
Cities("Los Angeles", "4"),
Cities("Chicago", "5"),
Cities("Houston", "6")
)

And that’s all. Thank you for reading.

If you tried and like it, you can like the post to support me. You can also follow me to learn more about the Android Kotlin and Jetpack Libraries.