I am migrating my android xml layouts to compose and have hit an issue when trying to implement a drop down menu in compose that supports the following xml version of a dropdown menu
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="@string/my_title" android:enabled="false" />
<group android:id="@+id/my_group" android:checkableBehavior="single">
<item
android:id="@+id/my_allocate"
android:icon="@drawable/my_allocate"
android:title="@string/context_menu_allocate" />
<item
android:id="@+id/my_delete"
android:icon="@drawable/my_delete"
android:title="@string/context_menu_delete" />
<item
android:id="@+id/my_context"
android:icon="@drawable/my_context"
android:title="@string/context_menu" />
</group>
</menu>
is this possible in compose?
why doesnt androidx.compose.material3.DropdownMenu
&
androidx.compose.material3.DropdownMenuItem
support dading groups
You can do something like this:
data class MenuItem(
val name: String,
val icon: ImageVector,
val selectedIcon: ImageVector,
val selected: Boolean = false
)
@Composable
fun Menu() {
val menuItems = remember {
mutableStateListOf(
listOf(
MenuItem(
name = "Home",
icon = Icons.Outlined.Home,
selectedIcon = Icons.Filled.Home,
selected = false
),
MenuItem(
name = "Favorites",
icon = Icons.Outlined.FavoriteBorder,
selectedIcon = Icons.Filled.Favorite,
selected = false
)
),
listOf(
MenuItem(
name = "Home",
icon = Icons.Outlined.Home,
selectedIcon = Icons.Filled.Home,
selected = false
),
MenuItem(
name = "Favorites",
icon = Icons.Outlined.FavoriteBorder,
selectedIcon = Icons.Filled.Favorite,
selected = false
)
)
)
}
val onClick = { groupId: Int, selectedItemIndex: Int ->
val newGroup: MutableList<MenuItem> = mutableListOf()
menuItems[groupId].forEachIndexed { index, item ->
newGroup.add(item.copy(selected = index == selectedItemIndex))
}
menuItems[groupId] = newGroup
}
DropdownMenu(expanded = true, onDismissRequest = { }) {
menuItems.forEachIndexed { groupIndex, group ->
group.forEachIndexed { index, item ->
DropdownMenuItem(
text = { Text(text = item.name) },
onClick = { onClick(groupIndex, index) },
leadingIcon = {
Icon(
imageVector = if (item.selected) item.selectedIcon else item.icon,
contentDescription = item.name
)
},
trailingIcon = {
RadioButton(
selected = item.selected,
onClick = { onClick(groupIndex, index) }
)
}
)
}
if (groupIndex < menuItems.size - 1) {
HorizontalDivider()
}
}
}
}
This is the result:
This code creates the menu view with the expected behavior. You can use the same logic to build a side menu or else.