'Jetpack Compose BottomSheet

I have started to learn jetpack compose. I want to show bottomsheet in click of IconButton.But i got error @Composable invocations can only happen from the context of a @Composable function how I can implement this logic.

Here is ui screen enter image description here

Here is code

@RequiresApi(Build.VERSION_CODES.O)
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun AddTaskScreen(navController: NavController) {
    var taskTitle by remember { mutableStateOf("") }
    val currentDate = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date())
    var taskDescription by remember { mutableStateOf("") }
    val taskDuration by remember { mutableStateOf(currentDate.toString()) }
    val taskTypes = listOf("Urgent", "Medium", "High")
    var expanded by remember { mutableStateOf(false) }
    var selectedOptionText by remember { mutableStateOf(taskTypes[0]) }
    val clickHandler: () -> Unit = {
       DateBottomSheet()
    }
    Column() {
        AppToolBar(title = "AddTaskScreen") {
            navController.navigateUp()
        }

        OutlinedTextField(
            value = taskTitle,
            label = { Text(text = "Please input task title") },
            onValueChange = { text -> taskTitle = text },
            modifier = textFieldModifier
        )
        OutlinedTextField(
            value = taskDescription,
            label = { Text(text = "Please input task description") },
            onValueChange = { text -> taskDescription = text },
            modifier = textFieldModifier.height(200.dp)
        )

        ExposedDropdownMenuBox(
            expanded = expanded,
            onExpandedChange = {
                expanded = !expanded
            },
            modifier = Modifier
                .fillMaxWidth()
                .padding(20.dp)
        ) {
            OutlinedTextField(
                readOnly = true,
                value = selectedOptionText,
                onValueChange = { },
                label = { Text("Task priority") },
                trailingIcon = {
                    ExposedDropdownMenuDefaults.TrailingIcon(
                        expanded = expanded
                    )
                },
                modifier = Modifier.fillMaxWidth()
            )
            ExposedDropdownMenu(
                expanded = expanded,
                onDismissRequest = {
                    expanded = false
                }
            ) {
                taskTypes.forEach { selectionOption ->
                    DropdownMenuItem(
                        onClick = {
                            selectedOptionText = selectionOption
                            expanded = false
                        }
                    ) {
                        Text(text = selectionOption)
                    }
                }
            }

        }


        //task time textField
        OutlinedTextField(
            value = taskDuration,
            readOnly = true,
            label = { Text(text = "Please select task duration") },
            onValueChange = { text -> taskDescription = text },
            modifier = textFieldModifier,
            trailingIcon = {
                IconButton(
                    onClick = {
                    clickHandler.invoke()
                }) {
                    Icon(Icons.Filled.DateRange, contentDescription = "")
                }
            }
        )
    }
}

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun DateBottomSheet() {
    val bottomSheetScaffoldState = rememberBottomSheetScaffoldState(
        bottomSheetState = rememberBottomSheetState(
            initialValue = BottomSheetValue.Collapsed
        )
    )


    BottomSheetScaffold(
        sheetContent = {
            Column() {
                Text(text = "ThisIsBottomSheet")
                Text(text = "ThisIsBottomSheet")
                Text(text = "ThisIsBottomSheet")
                Text(text = "ThisIsBottomSheet")
                Text(text = "ThisIsBottomSheet")
            }
        },
        scaffoldState = bottomSheetScaffoldState
    ) {
       
    }

But i got error @Composable invocations can only happen from the context of a @Composable function how I can implement this logic



Solution 1:[1]

You can simply use mutabelState for handling your button click event to show Bottom Sheet.

You can do following changes ->

@RequiresApi(Build.VERSION_CODES.O)
@OptIn(ExperimentalMaterialApi::class)
@Composable
fun AddTaskScreen(navController: NavController) {
    var taskTitle by remember { mutableStateOf("") }
    val currentDate = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).format(Date())
    var taskDescription by remember { mutableStateOf("") }
    val taskDuration by remember { mutableStateOf(currentDate.toString()) }
    val taskTypes = listOf("Urgent", "Medium", "High")
    var expanded by remember { mutableStateOf(false) }
    var selectedOptionText by remember { mutableStateOf(taskTypes[0]) }
    
    var openBottomSheet by rememberSaveable { mutableStateOf(false) }

    Column() {
        AppToolBar(title = "AddTaskScreen") {
            navController.navigateUp()
        }

        OutlinedTextField(
            value = taskTitle,
            label = { Text(text = "Please input task title") },
            onValueChange = { text -> taskTitle = text },
            modifier = textFieldModifier
        )
        OutlinedTextField(
            value = taskDescription,
            label = { Text(text = "Please input task description") },
            onValueChange = { text -> taskDescription = text },
            modifier = textFieldModifier.height(200.dp)
        )

        ExposedDropdownMenuBox(
            expanded = expanded,
            onExpandedChange = {
                expanded = !expanded
            },
            modifier = Modifier
                .fillMaxWidth()
                .padding(20.dp)
        ) {
            OutlinedTextField(
                readOnly = true,
                value = selectedOptionText,
                onValueChange = { },
                label = { Text("Task priority") },
                trailingIcon = {
                    ExposedDropdownMenuDefaults.TrailingIcon(
                        expanded = expanded
                    )
                },
                modifier = Modifier.fillMaxWidth()
            )
            ExposedDropdownMenu(
                expanded = expanded,
                onDismissRequest = {
                    expanded = false
                }
            ) {
                taskTypes.forEach { selectionOption ->
                    DropdownMenuItem(
                        onClick = {
                            selectedOptionText = selectionOption
                            expanded = false
                        }
                    ) {
                        Text(text = selectionOption)
                    }
                }
            }

        }


        //task time textField
        OutlinedTextField(
            value = taskDuration,
            readOnly = true,
            label = { Text(text = "Please select task duration") },
            onValueChange = { text -> taskDescription = text },
            modifier = textFieldModifier,
            trailingIcon = {
                IconButton(
                    onClick = {
                    openBottomSheet = true
                }) {
                    Icon(Icons.Filled.DateRange, contentDescription = "")
                }
            }
        )
        if (openBottomSheet) {
            DateBottomSheet()
            
        }
    }
}

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun DateBottomSheet() {
    val bottomSheetScaffoldState = rememberBottomSheetScaffoldState(
        bottomSheetState = rememberBottomSheetState(
            initialValue = BottomSheetValue.Collapsed
        )
    )


    BottomSheetScaffold(
        sheetContent = {
            Column() {
                Text(text = "ThisIsBottomSheet")
                Text(text = "ThisIsBottomSheet")
                Text(text = "ThisIsBottomSheet")
                Text(text = "ThisIsBottomSheet")
                Text(text = "ThisIsBottomSheet")
            }
        },
        scaffoldState = bottomSheetScaffoldState
    ) {
       
    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1