I face a problem with DropdownMenu
in compose. The problem is when I click on the icon to show the menu, it shows in each morevert icon in the LazyColum
not only in the icon that is clicked as illustrated in the following image:
Code Screenshot:
var expanded by remember { mutableStateOf(false) }
LazyColumn(contentPadding = PaddingValues(16.dp)) {
items(items = schedules) { schedule ->
TimetableItem(
navigator = navigator,
viewModel = viewModel,
schedule = schedule,
expanded = expanded,
onExpandedChange = {expanded = it}
)
}
}
@Composable
fun TimetableItem(
navigator: DestinationsNavigator,
viewModel: TimetableViewModel,
schedule: TimetableEntity,
expanded: Boolean,
onExpandedChange: (Boolean) -> Unit
) {
Card(
modifier = Modifier
.padding(bottom = 16.dp)
.fillMaxSize(),
shape = RoundedCornerShape(5.dp),
elevation = 8.dp
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(modifier = Modifier.fillMaxWidth()) {
Text(
modifier = Modifier
.align(Alignment.Center),
text = "${schedule.timeFrom} - ${schedule.timeTo}",
fontSize = 16.sp
)
IconButton(
onClick = { onExpandedChange(true)},
modifier = Modifier.align(Alignment.CenterEnd)
) {
Icon(
imageVector = Icons.Default.MoreVert,
contentDescription = stringResource(R.string.more_option)
)
DropdownMenu(
expanded = expanded,
onDismissRequest = { onExpandedChange(false) }
) {
val options = listOf(R.string.delete_option,R.string.edit_option)
options.forEachIndexed { index, option ->
DropdownMenuItem(
onClick = {
onExpandedChange(false)
when(index){
0 -> viewModel.onDeleteSchedule(schedule)
1 -> navigator.navigate(AddEditLectureScreenDestination(timetableEntity = schedule)) }
}
) { Text(stringResource(option))}
}
}
}
}
CodePudding user response:
Since you have multiple dropdown menus, you can't use the same boolean variable for all of them.
In the case of multiple selection you need to create a list/map of the selected items, but in this case only one drop-down menu can be selected, so you can store an optional selected item (or its index) like this:
val expandedSchedule = remember { mutableStateOf<TimetableEntity?>(null) }
LazyColumn(contentPadding = PaddingValues(16.dp)) {
items(items = schedules) { schedule ->
TimetableItem(
navigator = navigator,
viewModel = viewModel,
schedule = schedule,
expanded = expandedSchedule == schedule,
onExpandedChange = { expanded ->
expandedSchedule = schedule.takeIf { expanded }
}
)
}
}
CodePudding user response:
Your problem is that all of your ExpandedItems
share the same expandedState
You can also simplify your code:
@Composable
fun TimetableItem(
schedule: TimetableEntity,
expanded: Boolean = false,
onClick: (index: Int) -> Unit
) {
val expandedState by remember { mutableStateOf(expanded) }
Card(
modifier = Modifier
.padding(bottom = 16.dp)
.fillMaxSize(),
shape = RoundedCornerShape(5.dp),
elevation = 8.dp
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(modifier = Modifier.fillMaxWidth()) {
Text(
modifier = Modifier
.align(Alignment.Center),
text = "${schedule.timeFrom} - ${schedule.timeTo}",
fontSize = 16.sp
)
IconButton(
onClick = { expandedState = true},
modifier = Modifier.align(Alignment.CenterEnd)
) {
Icon(
imageVector = Icons.Default.MoreVert,
contentDescription = stringResource(R.string.more_option)
)
DropdownMenu(
expanded = expanded,
onDismissRequest = { expandedState = false }
) {
val options = listOf(R.string.delete_option,R.string.edit_option)
options.forEachIndexed { index, option ->
DropdownMenuItem(
onClick = {
expandedState = false
onClick(index)
}
) { Text(stringResource(option))}
}
}
}
}
In this case you don't need much specific parameters anymore:
TimeTableItem(
schedule = schedule,
) { index ->
when(index){
0 -> viewModel.onDeleteSchedule(schedule)
1 ->navigator.navigate(
AddEditLectureScreenDestination(timetableEntity = schedule)
)
}
}