第 3 章:组件基础——按钮、图标按钮、文本按钮
按钮这玩意儿,说简单也简单,说复杂……嗯,我见过不少项目在按钮上翻车。尤其是我们做加密动画优化,按钮就是动画的触发器。点一下按钮,加密动画开始;点一下,解密完成。这中间的反馈,全靠按钮的交互状态撑起来。
Material 3 把按钮分成了三类:实心按钮(Filled Button)、图标按钮(Icon Button) 和 文本按钮(Text Button)。三类按钮的背后,其实是一套统一的状态系统。你想想看,如果你对每个按钮都单独写一套动画逻辑,那维护起来得疯。我个人习惯是把状态抽象出来,再根据按钮类型微调视觉表现。
3.1 实心按钮(Filled Button)
实心按钮是主角。背景色最重,对比度最高,用户一眼就知道“点这里”。我做过一个加密钱包的登录页,就是靠一个实心按钮的点击反馈动画来判断网络延迟——动画卡了,说明网络有问题。
关键属性:
- 状态:enabled / disabled / hover / focused / pressed
- 动画属性:elevation 变化、background color 过渡、ripple 扩散
- 加密场景:点击后立即触发加密动画,按钮自身 elevation 从 2 升到 6,模拟按下感
3.2 图标按钮(Icon Button)
图标按钮很克制。它没有背景,只有一个图标 + 一个可选的圆形遮罩。在加密界面上,我常把“收藏/解密”功能做成图标按钮——用户习惯。不过要注意:图标按钮的点击热区其实很大,别被小图标骗了。
它的状态变化比实心按钮更微妙。hover 时出现半透明遮罩,pressed 时遮罩加深。我个人建议在加密动画的“撤销”或“查看详情”场景里用这个,别用在主要操作上——用户容易忽略。
一个我踩过的坑:早期版本图标按钮的 disabled 状态只改了颜色,不改变遮罩大小。结果用户以为按钮死掉了。Matrial 3 现在规定 disabled 图标按钮的透明度降到 0.38,同时取消任何遮罩动画——这才对。
3.3 文本按钮(Text Button)
文本按钮是最低调的。没有背景,没有阴影,只有一行文字。在加密动画里,我通常拿它做“取消”或“跳过动画”之类的辅助操作。用户点它的时候,预期是快速响应,而不是华丽的动画过渡。
为什么?因为文本按钮的 pressed 状态只是文字颜色变化 + ripple,非常轻。如果强行给它加一个 300ms 的渐变动画,用户会觉得卡——我测试过,延迟超过 100ms 用户就会皱眉。
你看,三种按钮的设计初衷完全不同。我们做优化的时候,不是给每个按钮套同样的动画模板,而是要理解它天生适合什么。
三类按钮对比一览
| 类型 | 视觉重量 | 常用场景 | 动画重点 | 加密场景建议 |
|---|---|---|---|---|
| 实心按钮 | 高 | 主要操作、提交 | elevation + 背景过渡 | 触发加密动画主入口 |
| 图标按钮 | 中 | 工具栏、收藏、复制 | 遮罩 + 图标颜色 | 解密/查看/撤销 |
| 文本按钮 | 低 | 取消、跳过、次要操作 | 文字颜色 + ripple | 跳过动画或重置 |
状态共享:背后的统一模式
三类按钮虽然长相不同,但 Material 3 给它们统一的状态管理。你只需要理解一套规则:
- 所有按钮都有 enabled / disabled / hover / focused / pressed 五种状态
- 每个状态都对应一套 颜色 + 高度 + 形状 的配置
- 动画过渡时长由 duration 控制,默认 200ms – 这是 Material 的运动原则
前阵子我重构一个加密 App,发现所有按钮的 pressed 状态动画用了 300ms,而 hover 用了 100ms。结果用户快速连点时,动画还没跑完就又触发新的状态,界面一顿乱闪。后来我把所有状态动画统一到 150ms,问题解决。这玩意儿,说白了就是状态机的节奏控制。
与加密动画的关联
现在想象一下:用户点了一个 实心按钮,触发了 AES 加密动画。动画持续 800ms,在这 800ms 内按钮应该保持 pressed 风格,并显示一个环形进度。动画结束后按钮恢复到正常状态,并且触发一个成功反馈(比如背景变绿 200ms 然后复原)。
这个流程里,按钮的状态变化就是加密动画的“节拍器”。如果按钮的状态跳变太早或太晚,用户会感觉动画脱节。所以我建议:
- 加密进行中:按钮 disabled + 显示等待指示器
- 加密完成:按钮 enabled + 短暂的颜色反馈
- 加密失败:按钮 enabled + 红色抖动动画(注意抖动幅度别太大,3px 就够了)
核心思路: 按钮状态本质上是一种用户反馈信号。加密动画的每一步都该映射到按钮状态的变化上。别让按钮“静止”在动画中间。
本章知识体系
看这张图就清楚了:三种按钮共享同一套底层状态机制,只是视觉侧重点不同。当你理解了状态系统,再去设计加密动画的触发、进行中和完成反馈,就会顺手很多。我的建议是:先统一管理按钮状态的变化时长,再针对不同类型微调颜色和 elevation。
MaterialStateProperty.resolveWith 来统一配置状态。不要把每个状态的颜色写死,而是写成一个函数——这样后期调动画曲线时,改一处就行。