Button:从静态圆角到按压形变 · AndroidX 源码指南
AAndroidX 源码指南
ANDROIDX / COMPOSE / MATERIAL 3

Button:从静态圆角到按压形变

理解 Button 的普通重载与 ButtonShapes 重载,以及 shapes() 和 shapesFor(height) 的区别。

为什么主题开了,按钮还没变形

Button 同时保留了普通 shape: Shape 重载和新的 shapes: ButtonShapes 重载。只有后者持有“常态形状 + 按压形状”,才能在交互状态之间变化。

官方 sample 的最小用法就是:

Button(
    onClick = {},
    shapes = ButtonDefaults.shapes(),
) {
    Text("Button")
}

这也是为什么不能只靠 MaterialExpressiveTheme 自动给所有按钮增加形变:是否使用新重载,是组件调用点自己选择的。

shapes()shapesFor(height)

shapes()

直接返回当前主题缓存的默认 ButtonShapes。源码使用 small button token 的常态与按压形状。

shapesFor(height)

先按给定高度归入 extra small / small / medium / large / extra large 档,再选择相应 pressedShape。

因此,标准小按钮可以用 shapes();当你明确使用不同容器高度时,shapesFor(buttonHeight) 能让按压形状与尺寸档位匹配。

val height = ButtonDefaults.LargeContainerHeight

Button(
    onClick = {},
    modifier = Modifier.heightIn(min = height),
    shapes = ButtonDefaults.shapesFor(height),
) {
    Text("Large action")
}

自定义两种状态

Button(
    onClick = {},
    shapes = ButtonDefaults.shapes(
        shape = RoundedCornerShape(24.dp),
        pressedShape = RoundedCornerShape(8.dp),
    ),
) {
    Text("Morph")
}

ButtonShapes 的两个 shape 都是 CornerBasedShape 时,形状才能按实现预期平滑插值。自定义前先保证交互反馈没有损害文字空间和可点击区域。

哪些按钮支持

当前 public API 中,ButtonElevatedButtonFilledTonalButtonOutlinedButtonTextButton 都有接收 ButtonShapes 的重载;官方 samples 也分别提供了 animated shape 示例。

源码依据

  • 默认 shapes:Button.kt:1165-1188
  • 按高度选择:Button.kt:1541-1562
  • 官方示例:ButtonSamples.kt:49-124
  • 公共 API:material3/api/current.txt 中的 Button overloads 与 ButtonShapes