Using ListPopupWindow for dropdown menu in Android

Spinner is the default option for creating dropdown menu in Android, but Spinner doesn’t place the dropdown menu exactly underneath the list header. Here is an alternative to Spinner which makes the dropdown menu to show up exactly underneath the list header.

It’s a RelativeLayout containing a TextView, an ImageView and a View. The TextView for showing the header of the list, the ImageView is a dropdown arrow icon placed on top of the TextView to the right, and the View is a 1dp height filled with a background color to use as a bottom border. When the TextView receives a click event, a ListPopupWindow will be placed right under the TextView giving an illusion of dropdown motion.

MainActivity.kt

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.ListPopupWindow
import kotlinx.android.synthetic.main.activity_main.*
import java.util.ArrayList

class MainActivity : AppCompatActivity() {

    private lateinit var placeTypes: ArrayList<String>
    private lateinit var placeTypesDropdownView: ListPopupWindow

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val dropDownHeight = 800
        placeTypes = getResources().getStringArray(R.array.place_types).toCollection(ArrayList())
        if (placeTypes.get(0) != getString(R.string.pick_place_type)) {
            placeTypes.add(0, getString(R.string.pick_place_type))
        }
        placeTypesDropdownView = ListPopupWindow(this)
        placeTypesDropdownView.setAdapter(ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, placeTypes))
        placeTypesDropdownView.setAnchorView(tv_place_type)
        placeTypesDropdownView.setHeight(dropDownHeight)
        placeTypesDropdownView.setModal(true)
        tv_place_type.post({
            placeTypesDropdownView.setWidth(tv_place_type.getMeasuredWidth())
        })
        placeTypesDropdownView.setOnItemClickListener({ adapterView, view, position, viewId ->
            tv_place_type.setText(placeTypes.get(position))
            placeTypesDropdownView.dismiss()
        })
        tv_place_type.setOnClickListener({
            placeTypesDropdownView.show()
        })

    }
}

strings.xml, the list items are defined here in the strings resource file.

<resources>
    <string name="app_name">Dropdown ListPopupWindow</string>

    <string name="pick_place_type">Select Place Type</string>
    <string-array name="place_types">
        <item>Restaurant</item>
        <item>Cafe</item>
        <item>Gas Stations</item>
        <item>Shopping</item>
        <item>Hotels</item>
        <item>Airport</item>
        <item>Transit Stations</item>
        <item>Banks</item>
        <item>School</item>
        <item>Church</item>
    </string-array>

</resources>

activity_main.xml, the dropdown list layout.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="20dp"
    tools:context="com.example.dropdownlistpopupwindow.MainActivity">

    <RelativeLayout
        android:id="@+id/rl_place_type_container"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="5">
        <TextView
            android:id="@+id/tv_place_type"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/pick_place_type"/>
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:src="@drawable/ic_arrow_drop_down_black"/>
        <View
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:background="#eee"
            android:layout_below="@+id/tv_place_type"/>
    </RelativeLayout>

</android.support.constraint.ConstraintLayout>

drop down arrow icon: https://material.io/icons/#ic_arrow_drop_down

Complete example in Github

Search within Codexpedia

Custom Search

Search the entire web

Custom Search