M3E 设计系统
ANDROIDX / COMPOSE / MATERIAL 3
ToggleButton:状态不是点击动画
理解 checked 状态、三套形状以及不同 ToggleButton 变体,不把它当成普通 Button 使用。
它和普通 Button 的根本区别
普通按钮表达一次动作;ToggleButton 表达一个可保持的二元状态。组件不会替你保存这个状态,checked 与 onCheckedChange 仍然由调用者连接:
var checked by remember { mutableStateOf(false) }
ToggleButton(
checked = checked,
onCheckedChange = { checked = it },
) {
Text("收藏")
}这段就是 AndroidX sample 的基本数据流。点击后能否保持选中,取决于你是否在回调中更新 checked。
它有三个形状
ToggleButtonShapes 不是普通 Button 的两个 shape,而是:
| 属性 | 使用时机 |
|---|---|
shape | 未选中、未按压 |
pressedShape | 手指或鼠标正在按压 |
checkedShape | 已选中 |
官方 sample 给出了方形变圆形的最小例子:
val shapes = ToggleButtonShapes(
shape = ToggleButtonDefaults.squareShape,
pressedShape = ToggleButtonDefaults.pressedShape,
checkedShape = ToggleButtonDefaults.roundShape,
)
ToggleButton(
checked = checked,
onCheckedChange = { checked = it },
shapes = shapes,
) {
Text("Button")
}当三者都是 CornerBasedShape 时,源码会做形状插值;出现其他 Shape 时则按状态切换,不保证同样的平滑 morph。
默认已经按高度选形状
ToggleButton 的默认参数不是固定 shapes(),而是:
shapes = ToggleButtonDefaults.shapesFor(ButtonDefaults.MinHeight)如果你改成 medium、large 等高度,应同时传入对应的 shapesFor(height) 和 contentPaddingFor(height),否则视觉尺寸变了,形状与内边距仍可能停留在 small 档。
变体怎么选
ToggleButton:主要与 tonal 颜色之间切换。ElevatedToggleButton:需要阴影层级。FilledTonalToggleButton:更柔和的填充强调。OutlinedToggleButton:未选中时保留边框;源码默认在 checked 时返回null边框。IconToggleButton:内容只有图标时优先使用,语义和尺寸更匹配。
单选和多选语义
ToggleButton 实现默认给 Surface 设置的是 Role.Checkbox。如果一组按钮只能选一个,AndroidX 的 connected group sample 会额外设置 Role.RadioButton。视觉上连在一起不等于无障碍语义已经正确。
复制即用
收藏开关的最小实现:
import androidx.compose.material3.ToggleButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@Composable
fun FavoriteToggle() {
var checked by remember { mutableStateOf(false) }
ToggleButton(
checked = checked,
onCheckedChange = { checked = it },
) {
Text(if (checked) "已收藏" else "收藏")
}
}方形选中变圆形(三套形状):
import androidx.compose.material3.ToggleButton
import androidx.compose.material3.ToggleButtonDefaults
import androidx.compose.material3.ToggleButtonShapes
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@Composable
fun ShapeMorphToggle() {
var checked by remember { mutableStateOf(false) }
val shapes = ToggleButtonShapes(
shape = ToggleButtonDefaults.squareShape,
pressedShape = ToggleButtonDefaults.pressedShape,
checkedShape = ToggleButtonDefaults.roundShape,
)
ToggleButton(
checked = checked,
onCheckedChange = { checked = it },
shapes = shapes,
) {
Text("Button")
}
}改大高度时记得同步 shapesFor(height) 和 contentPaddingFor(height)。