✨ 核心修饰符 Modifier.animateContentSize() 是 Jetpack Compose 中用于监听组件尺寸变化并自动生成平滑过渡动画的利器。当内容大小改变(例如文本行数增减、图片缩放、布局展开/收起),它会驱动尺寸以弹簧或补间动画渐变,而非突兀跳变。
| 特性 | 说明 |
|---|---|
| 🎯 动画类型 | 尺寸插值 (Size interpolation) + 弹簧效果 (Spring) |
| ⚙️ 参数 | animationSpec 自定义 (默认 spring()) |
| 🧩 适用场景 | 文本展开/收起、卡片扩展、列表项动态高度 |
| 📦 依赖 | 无需额外库,compose.animation 内置 |
👇 点击按钮切换 展开/收起,animateContentSize 让文本区域平滑伸缩。
@Composable
fun ExpandableText() {
var expanded by remember { mutableStateOf(false) }
val maxLines = if (expanded) Int.MAX_VALUE else 3
Column(
modifier = Modifier
.fillMaxWidth()
.animateContentSize( // ✨ 核心动画
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessLow
)
)
.padding(16.dp)
.background(Color(0xFFF7F0E6), shape = RoundedCornerShape(20.dp))
) {
Text(
text = longArticle, // 长文本内容
maxLines = maxLines,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.bodyLarge
)
Spacer(modifier = Modifier.height(8.dp))
TextButton(onClick = { expanded = !expanded }) {
Text(if (expanded) "👆 收起" else "👇 展开更多")
}
}
}
💡 当 maxLines 变化 → 组件高度改变 → animateContentSize 自动驱动过渡动画,无需手动计算。
通过 animationSpec 控制弹性、时长。推荐组合:
| 参数 | 效果 | 推荐值 |
|---|---|---|
| dampingRatio | 阻尼比 (越小越弹) | 0.3 ~ 0.6 (bouncy) |
| stiffness | 刚度 (越大越快) | StiffnessLow ~ StiffnessMedium |
| Spring | 默认弹簧动画 | spring() 即可 |
| tween | 补间动画 (更线性) | tween(300, easing = FastOutSlowIn) |
🎨 中小学生色系建议:配合柔和背景 (如 #FFF2E5) 和圆润卡片,让动画更亲切。
⬆️ 状态驱动 → 修饰符拦截尺寸变化 → 自动生成流畅动画
animateContentSize 内部频繁重组,使用 key 稳定子树。animateItemPlacement 替代。tween(300, easing = FastOutSlowIn) 获得更柔和的展开效果。clipToBounds() 防止动画过程中内容超出边界。将以下代码复制到 Compose 项目中即可体验:
@Preview
@Composable
fun AnimatedSizePreview() {
var isExpanded by remember { mutableStateOf(false) }
Surface(color = Color(0xFFFEF7EF)) {
Column(
modifier = Modifier
.padding(24.dp)
.animateContentSize(spring(dampingRatio = 0.5f, stiffness = 300f))
.background(Color(0xFFFFF0E0), RoundedCornerShape(28.dp))
.padding(20.dp)
) {
Text(
text = "🌟 在中小学生色系下,动画更活泼!\nCompose 让过渡变得简单又有趣。",
maxLines = if (isExpanded) Int.MAX_VALUE else 2,
overflow = TextOverflow.Ellipsis,
fontSize = 18.sp,
color = Color(0xFF2D4A4A)
)
Spacer(Modifier.height(12.dp))
TextButton(onClick = { isExpanded = !isExpanded }) {
Text(if (isExpanded) "🔼 收起" else "🔽 展开", fontWeight = FontWeight.Bold)
}
}
}
}