在Jetpack Compose中实现垂直网格视图的宽度适配问题
Compose FlowRow卡片宽度适配问题
我的代码
@Composable fun VerticalImageCards(toolsList: List<HealthTool>) { val domainName = stringResource(id = R.string.media_url) FlowRow(mainAxisSpacing = 8.dp, crossAxisSpacing = 16.dp, modifier = Modifier .fillMaxWidth() .padding(vertical = 16.dp), mainAxisSize = SizeMode.Wrap) { for (i in toolsList) { val imgUrl = "$domainName${i.url}" ToolsCardLayout(cardTitle = i.title, imgUrl = imgUrl) } } }
@Composable fun ToolsCardLayout( imgUrl: String, cardTitle: String, ) { Box(modifier = Modifier.clickable {}) { AsyncImage(model = imgUrl, contentDescription = null, contentScale = ContentScale.Crop, modifier = Modifier.fillMaxWidth()) Box(modifier = Modifier .size(32.dp) .align(Alignment.TopEnd)) { Image(painter = painterResource(id = R.drawable.schedule), contentDescription = null, modifier = Modifier .fillMaxSize() .padding(top = 8.dp, end = 8.dp), contentScale = ContentScale.Fit) } } Card(modifier = Modifier .height(44.dp) .fillMaxWidth()) { Text(text = cardTitle, style = MaterialTheme.typography.h6, modifier = Modifier .padding(horizontal = 16.dp, vertical = 8.dp) .clip(RoundedCornerShape(bottomStart = 8.dp, bottomEnd = 8.dp))) } }
代码说明
- 从服务器获取包含工具图片、标题、描述的工具详情列表
imgUrl:工具图片的完整链接cardTitle:工具名称
问题描述
Card组件会占满FlowRow的整个宽度。之前硬编码数据时,给卡片加weight(1f)可以解决该问题,但加载后端返回的数据后,这个方法不再生效。此外该网格布局用于首页,不能设置为可滚动。
解决方案
问题核心是FlowRow子项未设置宽度约束,且ToolsCardLayout内部使用fillMaxWidth()导致宽度失控,可通过以下两种方式修复:
方式1:基于权重分配宽度
修改VerticalImageCards中ToolsCardLayout的调用逻辑,为每个子项添加权重约束:
for (i in toolsList) { val imgUrl = "$domainName${i.url}" ToolsCardLayout(cardTitle = i.title, imgUrl = imgUrl) .modifier.weight(1f, fill = false) // fill设为false避免强制拉伸 }
同时调整ToolsCardLayout的内部布局,用Column整合图片和卡片,避免并列布局的宽度冲突:
@Composable fun ToolsCardLayout( imgUrl: String, cardTitle: String, ) { Column(modifier = Modifier.clickable {}) { Box { AsyncImage(model = imgUrl, contentDescription = cardTitle, contentScale = ContentScale.Crop, modifier = Modifier.fillMaxWidth()) Box(modifier = Modifier .size(32.dp) .align(Alignment.TopEnd)) { Image(painter = painterResource(id = R.drawable.schedule), contentDescription = "日程标记", modifier = Modifier .fillMaxSize() .padding(top = 8.dp, end = 8.dp), contentScale = ContentScale.Fit) } } Card(modifier = Modifier .height(44.dp) .fillMaxWidth()) { Text(text = cardTitle, style = MaterialTheme.typography.h6, modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)) } } }
方式2:固定每行卡片数量
如果需要固定每行显示N个卡片,可直接计算卡片宽度:
@Composable fun VerticalImageCards(toolsList: List<HealthTool>) { val domainName = stringResource(id = R.string.media_url) val screenWidth = LocalConfiguration.current.screenWidthDp.dp val cardCountPerRow = 2 // 自定义每行卡片数量 val cardWidth = (screenWidth - (cardCountPerRow - 1) * 8.dp) / cardCountPerRow // 减去间距 FlowRow(mainAxisSpacing = 8.dp, crossAxisSpacing = 16.dp, modifier = Modifier .fillMaxWidth() .padding(vertical = 16.dp), mainAxisSize = SizeMode.Wrap) { for (i in toolsList) { val imgUrl = "$domainName${i.url}" ToolsCardLayout(cardTitle = i.title, imgUrl = imgUrl) .modifier.width(cardWidth) } } }
两种方式都能保证卡片宽度均匀分配,适配后端返回的任意数据量,且布局保持不可滚动状态。
内容的提问来源于stack exchange,提问作者Naman
相关产品推荐
相关产品推荐

