如何将LazyColumn的项置于Card内?遇Composable调用报错
问题解决:Jetpack Compose LazyColumn分组外层加Card的错误处理
你遇到的@Composable invocations can only happen from the context of a @Composable function错误,核心原因是直接在普通的forEach循环里调用Card这个@Composable函数——LazyColumn的content块属于LazyListScope,这里只能使用该作用域提供的扩展方法(比如item、items)来添加Composable内容,普通循环里不能直接调用Composable。
针对你要给整个分组加Card实现整体阴影的需求,正确的做法是把每个分组的标题+整个分组内容都包裹在LazyColumn的item中,让Card在@Composable上下文里被调用,同时用Column承载分组内的所有条目,实现整体包裹效果:
修正后的代码
@Composable fun ReceiptsListing(navController: NavController, context: Context, locale: Locale) { val mappedReceipts = receipts.groupBy { DateUtils.humanizeDatetime(context, locale, it.uploadDate.dateToLocalDateTime()) } val listState = rememberLazyListState() val coroutineScope = rememberCoroutineScope() LazyColumn( state = listState, modifier = Modifier .padding(horizontal = 16.dp) .padding(top = 70.dp) ) { mappedReceipts.forEach { (dateGroup, receiptsInGroup) -> // 每个分组对应LazyColumn的一个item item { // 分组标题 Text( text = dateGroup, modifier = Modifier .padding(top = 16.dp) .padding(bottom = 8.dp) ) // 包裹整个分组的Card Card(elevation = 4.dp) { Column { receiptsInGroup.forEachIndexed { index, receipt -> ReceiptItem( receipt = receipt, cardType = getCardType(index, receiptsInGroup.size), ) { navController.navigate( ReceiptFragmentDirections.actionReceiptFragment2ToReceiptDetailsFragment2(it) ) } } } } } } } }
关键改动说明
- 将分组内容放入
item块:每个分组的标题和Card都放在LazyColumn的itemlambda中,确保所有Composable调用都处于@Composable上下文,解决错误提示问题。 - 用Column承载分组内条目:Card内部使用Column遍历分组下的所有ReceiptItem,让整个分组内容都在同一个Card中,实现整体阴影效果,避免单个Card的底部多余线条。
- 如果分组条目过多:如果分组内条目数量很大,担心性能问题,可以把Card内部的Column换成嵌套的
LazyColumn,并给嵌套的LazyColumn设置合适的高度(比如Modifier.heightIn(max = 400.dp)),避免滚动冲突。
内容的提问来源于stack exchange,提问作者kamaal4
相关产品推荐
相关产品推荐

