Omar
Omar

Reputation: 37

DropdownMenu in Compose opens in every Morevert icon in LazyColum

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:

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))}
                            }
                        }
    
                    }
                }

Upvotes: 2

Views: 1185

Answers (2)

Chris Pi
Chris Pi

Reputation: 612

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
    ) {
        var 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 = expandedState,
                            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)
      )                                    
   }
}

Upvotes: 1

Phil Dukhov
Phil Dukhov

Reputation: 87884

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 } 
            }
        )
    }
}

Upvotes: 2

Related Questions