解决@Composable仅能在@Composable函数上下文调用的编译错误
编译错误修复:@Composable invocations can only happen from the context of a @Composable function
错误原因
clickable修饰符的点击回调是普通非Composable上下文,不允许直接调用被@Composable注解标记的组件函数。你当前代码在Card的点击回调里直接调用Alert()组件,触发了这个编译限制。
Jetpack Compose是状态驱动的UI框架,弹窗这类条件显示的组件不能在事件回调里直接插入构图树,必须通过状态变量控制组件是否在Composable上下文里被渲染。
修复步骤
- 将控制弹窗显示的状态变量从
Alert()组件内部上移到Screen_A的Composable作用域中 - Card的点击回调里仅修改弹窗状态为显示,不直接调用Alert组件
- 将Alert组件放置在
Screen_A的Composable构图层级中,根据状态值判断是否渲染 - 给Alert组件传入关闭回调,在触发关闭操作时修改状态为隐藏
修正后代码
@Composable fun Screen_A_with_WithTopBar(navController: NavController) { Scaffold( topBar = { TopAppBar( title = { Text(text = "Top App Bar") }, navigationIcon = { IconButton(onClick = { navController.navigate(Screen.Home.route) }) { Icon(Icons.Filled.Menu, "backIcon") } }, backgroundColor = MaterialTheme.colors.primary, contentColor = Color.White, elevation = 10.dp ) }, content = { Screen_A(navController) } ) } @Composable fun Screen_A(navController: NavController) { val context = LocalContext.current // 弹窗显示状态上移到此处,初始为不显示 val openDialog = remember { mutableStateOf(false) } Column( verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier .fillMaxSize() ) { Text( text = "Dooro", fontSize = 42.sp ) Spacer(modifier = Modifier.height(33.dp)) Row( verticalAlignment = Alignment.Top, horizontalArrangement = Arrangement.SpaceAround, modifier = Modifier .fillMaxWidth() .padding(12.dp), ) { Card( modifier = Modifier .width(150.dp) .height(80.dp) .clickable { // 点击仅修改状态,不直接调用Composable组件 openDialog.value = true }, shape = RoundedCornerShape(7.dp), elevation = 7.dp ) { Text( text = "None", fontSize = 24.sp, fontWeight = FontWeight.Bold, textAlign = TextAlign.Center ) } } // END Row } // 在Composable上下文里根据状态渲染弹窗 if (openDialog.value) { Alert( onDismiss = { openDialog.value = false } ) } } // 弹窗组件改为接收关闭回调,不自己持有显示状态 @Composable fun Alert(onDismiss: () -> Unit) { AlertDialog( onDismissRequest = onDismiss, title = { Text(text = "Title") }, text = { Text( "This area typically contains the supportive text " + "which presents the details regarding the Dialog's purpose." ) }, buttons = { Row( modifier = Modifier.padding(all = 8.dp), horizontalArrangement = Arrangement.Center ) { Button( modifier = Modifier.fillMaxWidth(), onClick = onDismiss ) { Text("Dismiss") } } } ) }
额外说明:如果使用Compose 1.0+版本,也可以用
rememberSaveable替代remember保存弹窗状态,避免屏幕旋转等配置变更后状态丢失。
内容的提问来源于stack exchange,提问作者Mohammed
相关产品推荐
相关产品推荐

