Jetpack Compose中ElevatedCard异常阴影问题排查
问题:ElevatedCard 添加组件后阴影异常
正常显示状态
初始仅包含文本时,ElevatedCard 显示正常:
对应代码:
ElevatedCard( content = { Text( fontSize = 20.sp, text = "All cars", modifier = Modifier.fillMaxWidth().padding(horizontal = 10.dp, vertical = 12.dp) ) }, onClick = { }, modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp) )
异常显示状态
添加 IconButton 和展开文本后,卡片角落出现异常阴影,侧边、上下区域阴影几乎消失,折叠和展开状态均存在该问题:
折叠状态:
展开状态:
对应代码:
var expanded by rememberSaveable { mutableStateOf(false) } ElevatedCard( content = { Row( content = { Text( fontSize = 20.sp, text = "All cars", modifier = Modifier.weight(weight = 1f).padding(start = 6.dp) ) IconButton( onClick = { expanded = !expanded }, checked = expanded, icon = R.drawable.ic_chevron, contentDescription = R.string.expand, tint = MaterialTheme.colorScheme.secondary ) }, modifier = Modifier.padding(horizontal = 4.dp), verticalAlignment = Alignment.CenterVertically ) ScaleVisible( content = { Text( fontSize = 14.sp, color = Color.DarkGray, text = "All cars from the latest catalog.", modifier = Modifier.padding(bottom = 4.dp) ) }, visible = expanded, modifier = Modifier.padding(horizontal = 10.dp) ) }, onClick = { expanded = !expanded }, modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp).animateContentSize() )
多次调整卡片内外边距无改善,请问问题出在哪里?
自定义组件代码
@Composable fun ScaleVisible( visible: Boolean, modifier: Modifier = Modifier, duration: Int = AnimationConstants.DefaultDurationMillis, content: @Composable AnimatedVisibilityScope.() -> Unit ) { AnimatedVisibility( content = content, visible = visible, modifier = modifier, enter = scaleIn(tween(duration)), exit = scaleOut(tween(duration)) ) } @Composable @OptIn(ExperimentalMaterial3Api::class, ExperimentalAnimationGraphicsApi::class) fun Icon( modifier: Modifier = Modifier, iconSize: Dp = 30.dp, @DrawableRes icon: Int, visible: Boolean = true, checked: Boolean? = null, @StringRes contentDescription: Int, tint: Color = LocalContentColor.current, ) { ScaleVisible( content = { TooltipBox( tooltip = { PlainTooltip( contentColor = Color.White, containerColor = MaterialTheme.colorScheme.secondary ) { Text( fontWeight = FontWeight.Light, text = stringResource(id = contentDescription) ) } }, content = { Icon( tint = tint, painter = if (checked != null) rememberAnimatedVectorPainter( atEnd = checked, animatedImageVector = AnimatedImageVector.animatedVectorResource(id = icon) ) else painterResource(id = icon), modifier = Modifier.size(size = iconSize), contentDescription = onString(id = contentDescription) ) }, state = rememberTooltipState(), positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider() ) }, visible = visible, modifier = modifier ) } @Composable fun IconButton( modifier: Modifier = Modifier, iconSize: Dp = 30.dp, @DrawableRes icon: Int, enabled: Boolean = true, visible: Boolean = true, checked: Boolean? = null, @StringRes contentDescription: Int, tint: Color = LocalContentColor.current, onClick: () -> Unit ) { ScaleVisible( content = { IconButton( content = { val color = if (enabled) tint else Color.LightGray Icon( icon = icon, tint = color, checked = checked, iconSize = iconSize, contentDescription = contentDescription ) }, onClick = onClick, enabled = enabled ) }, visible = visible, modifier = modifier ) }
问题原因及解决方法
问题出在**animateContentSize()修饰符与ElevatedCard的阴影渲染冲突**,同时自定义IconButton嵌套多层ScaleVisible(即AnimatedVisibility),叠加动画干扰了卡片的布局测量,导致阴影边界计算异常。
具体修复步骤:
将
animateContentSize()从ElevatedCard移到卡片内部
把动画逻辑限定在可展开区域,避免影响整个卡片的阴影计算:// 替换原卡片内的Column/布局根节点 Column(modifier = Modifier.padding(16.dp).animateContentSize()) { // 原Row和ScaleVisible内容 }简化动画嵌套层级
自定义IconButton已经嵌套了ScaleVisible,卡片本身又有点击展开逻辑,多层动画会导致布局测量偏差。可以先移除IconButton内的ScaleVisible测试,确认问题后再按需保留外层动画。遵循Material3内边距规范
给ElevatedCard的内容区域添加标准内边距(如16.dp),避免内容紧贴卡片边缘干扰阴影渲染。
修复后的示例代码:
var expanded by rememberSaveable { mutableStateOf(false) } ElevatedCard( content = { Column(modifier = Modifier.padding(16.dp).animateContentSize()) { Row( verticalAlignment = Alignment.CenterVertically ) { Text( fontSize = 20.sp, text = "All cars", modifier = Modifier.weight(1f) ) IconButton( onClick = { expanded = !expanded }, checked = expanded, icon = R.drawable.ic_chevron, contentDescription = R.string.expand, tint = MaterialTheme.colorScheme.secondary ) } ScaleVisible( content = { Text( fontSize = 14.sp, color = Color.DarkGray, text = "All cars from the latest catalog.", modifier = Modifier.padding(top = 8.dp) ) }, visible = expanded ) } }, onClick = { expanded = !expanded }, modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp) )
另外注意自定义Icon组件中的onString应为stringResource,这个笔误也可能间接影响布局稳定性。
内容的提问来源于stack exchange,提问作者Mark Delphi
相关产品推荐
相关产品推荐

