Reputation: 2169
What i am trying to do is to close the TopBar dropdown menu after clicking the dropdown item. It can be easily done, if i am putting the dropdown items directly inside the dropdown menu. But here i am trying to separate it as a composable for readability.
Here is my TopAppBar
@Composable
fun TopBar(
scope: CoroutineScope,
scaffoldState: ScaffoldState,
event: (AdminLaunchEvents) -> Unit,
navController: NavHostController
) {
val openDialog = remember { mutableStateOf(false) }
TopAppBar(
title = {
Text(text = "Main App Admin Area", fontSize = 18.sp)
},
actions = {
OverflowMenu() {
SettingsDropDownItem(onClick = {})
ModeDropDownItem(onClick = {})
LogoutDropDownItem(onClick = {
openDialog.value = true
})
}
},
backgroundColor = MaterialTheme.colors.primary,
contentColor = Color.White
)
if (openDialog.value) {
LogOutComponent(openDialog = openDialog, event = event,navController = navController)
}
}
And this is the OverFlowMenu
composable which contains the DropDown Menu
@Composable
fun OverflowMenu(content: @Composable () -> Unit) {
var showMenu by remember { mutableStateOf(false) }
IconButton(onClick = {
showMenu = !showMenu
}) {
Icon(
imageVector = Icons.Outlined.MoreVert,
contentDescription = "More",
)
}
DropdownMenu(
expanded = showMenu,
onDismissRequest = { showMenu = false }
) {
content()
}
}
Now given below is the DropDownItem
.
@Composable
fun SettingsDropDownItem(onClick: () -> Unit) {
DropdownMenuItem(onClick = onClick) {
Icon(
Icons.Filled.Settings,
contentDescription = "Settings",
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text("Settings")
}
}
What i am trying to do is, when i click the SettingsDroDownItem
, i need to capture the click event in the OverFlowMenu
composable to make the showMenu
false
, so as the hide the DropdownMenu
. I can get the click event in the TopAppBar
, but how to get it on DropDownMenu
.
How to do that?
Upvotes: 2
Views: 2273
Reputation: 87854
The first option is moving showMenu
state out of OverflowMenu
, as this is not the only composable which depends on the value. Something like this:
OverFlowMenu
:
@Composable
fun OverflowMenu(showMenu: Bool, setShowMenu: (Bool) -> Unit, content: @Composable () -> Unit) {
// ...
}
TopBar
:
actions = {
var (showMenu, setShowMenu) = remember { mutableStateOf(false) }
OverflowMenu(showMenu, setShowMenu) {
SettingsDropDownItem(onClick = {
openDialog.value = true
setShowMenu(false)
})
}
},
An other options is creating something like OverflowMenuScope
, and running SettingsDropDownItem
on this scope so it can close the menu itself:
OverflowMenu
:
interface OverflowMenuScope {
fun closeMenu()
}
@Composable
fun OverflowMenu(content: @Composable OverflowMenuScope.() -> Unit) {
var showMenu by remember { mutableStateOf(false) }
val scope = remember {
object: OverflowMenuScope {
override fun closeMenu() {
showMenu = false
}
}
}
//...
DropdownMenu(
expanded = showMenu,
onDismissRequest = { showMenu = false }
) {
scope.content()
}
}
SettingsDropDownItem
:
@Composable
fun OverflowMenuScope.SettingsDropDownItem(onClick: () -> Unit) {
DropdownMenuItem(onClick = {
closeMenu()
onClick()
}) {
Icon(
Icons.Filled.Settings,
contentDescription = "Settings",
modifier = Modifier.size(24.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text("Settings")
}
}
Upvotes: 5