Custom DropDownMenu In Android Compose With Selection
In this post I will show you how to implement a custom DropDownMenu in Android Compose that tracks the current selection with a checkmark icon.

In this post I will show you how to implement a custom DropDownMenu in Android Compose that tracks the current selection with a checkmark icon.

This is a fairly basic element but with a simple added feature to make it look better than out of the box. The checkmark will be added next to the currently selected DropDownMenuItem in the list each time the user accesses it.

I implemented a selection index held in a mutable state. This is updated each time the user selects a menu option.

This DropDownMenu In Android logic is implemented primarily in the foreach statement of creations. In the foreach statement, the selected index is check. If the index matches the selected index, then it will load an icon to the right side of the menu item. This marks the menu item as the currently selected option.

Code

This is the entire Composable. The element is a DropDownMenu Composable with a static list. The DropDownMenuItems are created in a foreachIndexed function so the index could be used as part of the selection tracking.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            SampleDropDownMenuTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Box(modifier = Modifier.fillMaxSize().padding(innerPadding), contentAlignment = Alignment.TopCenter){
                        DropDownMenu()
                    }
                }
            }
        }
    }
}

@Composable
fun DropDownMenu() {
    val categories: List<String> = listOf("Grocery", "Home", "Family", "Honey Do", "Work", "Bucket List", "Movies", "TV Shows", "Books", "Workout")
    var selectedIndex by remember { mutableStateOf(0) }
    var expanded by remember { mutableStateOf(false) }

    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(5.dp)
            .clickable {
                expanded = true
            }, horizontalArrangement = Arrangement.SpaceBetween
    ){
        OutlinedTextField(
            modifier = Modifier
                .fillMaxWidth(0.8f),
            value = if(selectedIndex < categories.size) categories[selectedIndex] else categories[0],
            enabled = false,
            onValueChange = {

            },
            colors = TextFieldDefaults.colors(disabledTextColor = Color.Black),
            textStyle = MaterialTheme.typography.bodyMedium,
            trailingIcon = {
                Icon(imageVector = Icons.Filled.ArrowDropDown, contentDescription = "Open Category Menu")
            }
        )

        Box(modifier = Modifier.padding(5.dp),
            contentAlignment = Alignment.BottomEnd) {
            DropdownMenu(
                modifier = Modifier.fillMaxWidth(0.85f).padding(5.dp),
                expanded = expanded,
                onDismissRequest = { expanded = false }
            ) {
                categories.forEachIndexed { index, category ->
                    DropdownMenuItem(
                        onClick = {
                            selectedIndex = index
                            expanded = false
                        },
                        text = {
                            Row(
                                modifier = Modifier.fillMaxWidth(),
                                horizontalArrangement = Arrangement.SpaceBetween){
                                Text(
                                    text = category,
                                    style = MaterialTheme.typography.headlineSmall,
                                    modifier = Modifier.padding(10.dp, bottom = 15.dp)
                                )
                                if(selectedIndex == index){
                                    Icon(imageVector = Icons.Filled.Check, contentDescription = "Currently selected ${category}")
                                }
                            }

                        }
                    )
                }
            }
        }
    }
}

Hope this was useful.

Leave a Reply

Your email address will not be published. Required fields are marked *