Creating & styling dropdown menus on Android

Stelios Papamichail
ITNEXT
Published in
5 min readJul 26, 2021

--

You can now find this and other posts over on my substack page at https://thatgreekengineer.substack.com/ !

I recently had to implement a customized dropdown menu for my app and it took me a long time to figure out what to style and how to do it properly in order to achieve the look and feel I was going for. So, in this article, I’ll go over how to customize an exposed dropdown menu using a TextInputLayout and an AutoCompleteTextView. We’re going to go from this:

Slightly customized exposed dropdown menu

to this:

Final exposed dropdown menu

What are exposed dropdown menus?

Exposed dropdown menus display the currently selected menu item above the list of options. Some variations can accept user-entered input. On Android, this functionality can be implemented using a TextInputLayout along with a nested AutocompleteTextView which are both components of Android’s material library. Let’s import the library into our project:

implementation ‘com.google.android.material:material:1.4.0’

I’m also going to be using ViewBinding for this tutorial, so make sure you enable it in your module’s build.gradle by adding the following:

android {
...
buildFeatures {
viewBinding true
}
}

Designing the basic layout

Let’s start by declaring the basic layout of a material exposed dropdown menu.

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/dateFilterContainer" style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:hint="@string/label">

<AutoCompleteTextView
android:id="@+id/datesFilterSpinner"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inputType="none"
tools:text="All Time"" />
</com.google.android.material.textfield.TextInputLayout>

Here we’re simply adding a TextInputLayout that contains an AutoCompleteTextView which will act as our dropdown. Pay attention to the inputType="none" line since that tells the AutoCompleteTextView that we’re not planning on entering any text details by hand. This in combination with the custom style we’re assigning to the TextInputLayout, will allow the AutoCompleteTextView to function like a spinner when clicked.

To learn more about the various available styles and customization options, take a look at Google's Menus — Material Design documentation.

Giving our dropdown a more custom look

Let’s begin with the color that we’ll use for the background of our dropdown.

<color name="pastel_orange_light">#FBE8DF</color>

Next, we’re going to create a new filter_spinner_dropdown_bg.xml drawable and use the following code to shape it:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/pastel_orange_light" />
<corners android:radius="20dp" />
</shape>

The last thing we’ll need, is a dropdown icon which will be placed at the end of the TextInputLayout. I used the down arrow from the free feather icon pack. Alright, now that we have all of our resources, let’s style our dropdown further.

First and foremost, we’re going to set the background of our TextInputLayout to the drawable that we created earlier.

Next up, we’re going to round the corners of the box that’s placed around the TextInputLayout (due to our selected style) by changing the radius of the various corners and also set the boxStrokeWidth and boxStrokeWidthFocused to 0dp since we don’t want any outline on our dropdown.

Furthermore, let’s add our custom dropdown arrow icon using the endIconDrawable attribute and also tint it to match our style using endIconTint.

We’re now done with styling the TextInputLayout, so let’s move onto the AutoCompleteTextView. Here we’re setting the background="@null" so that it doesn’t overlap with the background of our TextInputLayout.

Next, we specify a dropDownSelector drawable, which in this case is going to be the same drawable that we created earlier.

The dropDownSelector is a drawable that’s used to highlight an item when you click it.

For my app, I didn’t want anything like that to be visible, so I just set it to be the same as our background drawable.

Continuing on, adding the following lines will simply limit the text to a single line so that everything looks consistent and an ellipsis (...) will be added at the end of the text when it’s too long.

android:ellipsize="end"
android:maxLines="1"
android:singleLine="true"

We’re also going to add some padding around the top and bottom since for some reason, the nesting of an AutoCompleteTextView in a TextInputLayout, causes it to clip a bit to the TextInputLayout’s bounds.

Lastly, we’ll center and style our text a bit, and that’s it. Below is the final code.

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/typesFilterContainer" style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:background="@drawable/filter_spinner_dropdown_bg"
app:boxBackgroundColor="@color/pastel_orange_light"
app:boxCornerRadiusBottomEnd="20dp"
app:boxCornerRadiusBottomStart="20dp"
app:boxCornerRadiusTopEnd="20dp"
app:boxCornerRadiusTopStart="20dp"
app:boxStrokeWidth="0dp"
app:boxStrokeWidthFocused="0dp"
app:endIconDrawable="@drawable/ic_arrow_down"
app:endIconTint="@color/pastel_orange_txt_highlight">

<AutoCompleteTextView
android:id="@+id/typesFilter"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@null"
android:fontFamily="@font/lato" android:dropDownSelector="@drawable/filter_spinner_dropdown_bg"
android:ellipsize="end"
android:inputType="none"
android:maxLines="1"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:singleLine="true"
android:text="All Types"
android:textAlignment="center"
android:textColor="@color/pastel_orange_txt_highlight"
tools:ignore="LabelFor" />
</com.google.android.material.textfield.TextInputLayout>

You should now have something that looks a lot like this:

Output

Let’s see how we can populate our dropdown with items next!

Specifying dropdown items

In order to set the dropdown items for our menu, we need to use an ArrayAdapter<>() and pass in the context, item layout and a list of items. In this case, we’re going to use the predefined android.R.layout.simple_spinner_dropdown_item layout since it will cover our needs for now but you can also use a custom layout and customize it even further in a custom ArrayAdapter subclass. Let’s see the code so far:

val adapter = ArrayAdapter(
requireContext(), android.R.layout.simple_spinner_dropdown_item, arraylistOf("All Types", "Assignments", "Exam", "Lab")
)
binding?.typesFilterSpinner?.setAdapter(adapter)
binding?.typesFilterSpinner?.setText("All Types")

Great, now that our dropdown menu is populated with items, we’ll need to define a custom drawable to be used as the dropdown background since right now, the default white one will be used.

Using a custom dropdown background drawable

Once again, we’ll make use of our filter_spinner_dropdown_bg.xml drawable. Simply call the setDropDownBackgroundDrawable() on the AutoCompleteTextView and that will be it for the background.

binding?.typesFilterSpinner.setDropDownBackgroundDrawable(
ResourcesCompat.getDrawable(
resources,
R.drawable.filter_spinner_dropdown_bg,
null
)
)

Alright, we are finally done with the styling of our dropdown. It should now look something like this:

Final result

For our last part, we’ll see how to handle item click events!

Handling item click events

In order to be notified when a dropdown item is clicked, we’re going to simply define our own AdapterView.OnItemClickListener and use it in our AutoCompleteTextView.

binding?.typesFilterSpinner.onItemClickListener =
AdapterView.OnItemClickListener { parent, view, position, id->
// do something with the available information

}

This concludes this tutorial, you should now have a fully functional and great looking dropdown menu/spinner. If you have any suggestions, improvements or comments in general, please let me know down in the comments and I’ll do my best to incorporate them. Happy coding!

--

--