Home > Net >  DropdownMenu in Compose opens in every Morevert icon in LazyColum
DropdownMenu in Compose opens in every Morevert icon in LazyColum

Time:05-19

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

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