简介:面向Android等平台开发者的Material Design控件示例代码集,依据官方设计规范整理,帮助读者快速理解材料化界面中的层次、投影与动效语言,并在真实项目中灵活复用这些组件。压缩包共52个文件,以Java源码、XML布局和Gradle构建配置为主,辅以少量资源图片与项目配置文件,整体仅71KB,轻量易用;文件结构清晰,适合直接导入工程或对照查阅。示例覆盖Button、FloatingActionButton、TextInputLayout、CardView、Snackbar、BottomNavigationView、BottomSheet、进度条、对话框、滑块、开关/复选框以及AppBar/Toolbar等常用控件,几乎每一类都配有可直接运行的代码片段,能直观看到按钮浮动、卡片阴影、底部弹层、输入标签等交互效果,便于掌握属性设置与状态反馈。目前已有320人学习下载,整体可作为一份离线速查手册,既用于快速原型验证,也能减少查官方文档和调试控件的时间,尤其适合初中级开发者系统学习Material Design的实践要点。 这两年做客户端的同学应该都有个明显感受:Material Design早就不再是“一组样式规范”那么简单了,它已经长成了一整套从设计令牌到交互动效、再到跨端组件库的系统。而真正把项目从“原生感”拖到“精致感”的关键,往往不是设计稿多漂亮,而是对设计控件的掌握程度。
这篇文章我打算用“控件的系统化认知 + 关键细节拆解 + 踩坑实录”的方式,把我自己从照搬官方示例到能在实际项目里灵活组合控件的经验梳理一遍。适合刚接触 Material Design 的初级开发,也适合那些已经写过不少界面、但总觉得交互反馈不“跟手”的朋友。
1. 设计控件的理解方式:先忘掉单个控件,看整体交互语言
很多新手入门 Material Design 会犯一个共同的错误:一上来就盯着 Button、Card、Toolbar 逐个看属性。我可以直接说——这种学法效率很低,而且做出来的界面往往是“形似神不似”。真正应该先建立的,是三件事:状态、层级、动效。
1.1 状态是你最先要建立的意识
Material 控件和其他 UI 框架最大的不同,就是它对“状态”的刻画极其精细。一个按钮不只是“正常”和“点击”两种状态,而是有 enabled、disabled、focused、pressed、hovered、dragged 这一整套状态容器。控件之所以显得“活”,是因为每个状态都有对应的背景色调、透明度、高度变化。
如果用一句话总结,那就是:控件不是静态的样子,而是一组条件下可以组合呈现的反馈机制。理解了这一点,你再看官方文档里的 state layer、elevation overlay 这些概念,就会有一种“原来如此”的感觉。
1.2 层级由高度和面积共同决定
Material Design 里的“层级”主要由两个因素决定:控件自身的面积大小,以及它相对背景的高度偏移。高度偏移在 Android 里对应 elevation,它是“物理阴影”的来源;面积则决定了控件在视觉上的权重。
在实际项目里,我一般会根据功能优先级来确定控件的“体量”。主操作按钮用大号 Filled Button,次要操作用 Outlined Button,文字链接级别的操作用 Text Button——这不仅是美观问题,也是引导用户注意力的手段。这个优先级思维,比记住任何一条规范都更重要。
1.3 动效不是装饰,是空间关系的解释
Material 的运动系统讲究的是“真实世界的惯性”:控件从一个位置移动到另一个位置时,要遵循加速、减速、回弹这些物理直觉。官方提供了标准曲线、加速曲线、减速曲线三种基础插值方式,它们对应的是对象离场、入场、以及页面内移动的常见场景。
动效在我眼里是成本收益比最高的部分。你哪怕只给 RecyclerView 的 item 加一个 200ms 的透明度渐入,界面的精致程度都会上一个台阶。更具体的内容我会在第四节专门展开,这里先建个概念:动效=空间切换的说明书。
2. 核心控件的选型与配置:从实际需求出发
这一节咱们挑日常出镜率最高的几个控件,用“场景→选型→关键参数”的思路来拆解。你会发现,控件的很多属性如果不知道背后原因,硬背是背不住的。
2.1 按钮:不要只会改颜色
Material Design 的按钮家族大致分为三类:强调主要操作的 Filled Button、用于次要操作的 Outlined Button、以及用于三级操作的 Text Button。三类按钮在视觉重量、点击区域、场景匹配上都不同。
重点说两个常被忽略的配置:一个是android:minHeight,默认 48dp,这个值直接决定了触控热区大小,过小会影响手势体验;另一个是图标与文字的组合方式,MDC-Android 库提供了app:icon属性,你不需要手动在布局里塞两个子控件,直接设置这个属性会省掉大量的对齐问题。
我给项目做按钮统一配置的经验是,先把公共样式抽到styles.xml,比如:
<style name="Widget.App.FilledButton" parent="Widget.MaterialComponents.Button"> <item name="cornerRadius">20dp</item> <item name="android:minHeight">52dp</item> <item name="android:textSize">14sp</item> <item name="iconTint">@color/white</item> </style>这样全局替换主题时只需要改一个地方,不会出现二十个页面二十种按钮的失控场面。
2.2 文本框:容错设计才是体验的分水岭
文本输入框(TextInputLayout + TextInputEditText)是 Material 控件里最复杂的组件之一,因为它承担了标签浮动、错误提示、密码可见性切换、字符计数等多重职责。我见到最多的失误,是把 TextInputLayout 当成 FrameLayout 用,只套了一个 EditText,完全没发挥出它的能力。
我在实际项目里的推荐组合是:
hint用app:hintEnabled="true"保持默认浮动效果,但要注意加上android:paddingTop,否则文字变大时容易遮挡。- 错误提示用
app:errorEnabled="true",不要自己在下面再放一个 TextView 手动控制显示隐藏,那个做法维护成本极高。 - 密码输入框使用
app:endIconMode="password_toggle",图标和输入框内部绑定,不用再写点击事件去切换InputType。
如果表单校验失败,你可以直接调用ilPassword.error = "密码长度不足6位",控件会自动处理颜色、图标、动画,比自己手撸一套逻辑要省心得多。
2.3 卡片:圆角与高度有审美规律
CardView 早先还是 support 库时代的产物,现在 MDC-Android 的 MaterialCardView 提供了更多配置能力,包括自定义描边、可点击状态下的按压反馈,以及圆角大小设置。
个人经验是,圆角不是越大越好,12dp 以上就接近“胶囊化”,跟列表项的气质容易冲突。列表页里的卡片我一般用 8dp~12dp,配合 1dp~2dp 的描边,而不是一味依赖阴影,这样的层次感在浅色背景下更干净。
别忘了设置app:rippleColor与app:checkedIcon。如果你的卡片可点击,没有涟漪反馈的话,用户会觉得“点了没反应”,这是交互心理层面的硬伤。
2.4 AppBar 与 FAB:页面框架的骨架
AppBar 不只是放标题的容器,还承担了返回导航、操作入口、以及滚动折叠的角色。MDC-Android 里推荐使用MaterialToolbar而不是旧版 Toolbar,这样主题色、标题字体、溢出菜单样式会自动跟随全局配置。
悬浮按钮(FAB)的选型主要看尺寸:常规尺寸 56dp,适合主操作;小型 40dp,适合辅助操作。它的位置我建议和列表内容的边距保持统一,通常用layout_marginEnd="16dp"和layout_marginBottom="16dp",视觉上会更协调。如果页面滚动了,想让 FAB 跟着消失或呈现,配合第三节的布局联动,下面会讲到。
3. 主题、颜色与布局配合:控件不能脱离上下文
控件之所以难用,很多时候不是控件本身的问题,而是它所在的“上下文”没有搭对。这里的上下文,指的就是主题和布局。
3.1 主题是控件的总设计师
Material Design 控件在 Android 上高度依赖Theme.MaterialComponents.*主题,因为属性,如colorPrimary、colorSecondary、colorSurface、colorOnPrimary等,定义了控件从背景到文字的全部配色。
一个建议:所有颜色都通过主题属性间接引用,不要在布局里直接硬编码色值。比如你的背景色需要调整,你只需要改colorSurface,整个应用里的卡片、对话框、输入框都会统一变化。硬编码会破坏这个体系。
具体配置可以参考这个骨架:
<style name="Theme.App" parent="Theme.MaterialComponents.Light.NoActionBar"> <item name="colorPrimary">@color/primary</item> <item name="colorSecondary">@color/secondary</item> <item name="colorSurface">@color/surface</item> <item name="colorOnPrimary">@color/white</item> <item name="materialButtonStyle">@style/Widget.App.FilledButton</item> <item name="materialCardViewStyle">@style/Widget.App.Card</item> </style>这样设置后,你在 XML 里写<Button>,它会自动匹配全局样式,不需要每个页面单独指定。
3.2 CoordinatorLayout 是联动的基础
如果只用 FrameLayout 或 LinearLayout 做根布局,你其实只发挥了 Material 控件六成的功力。很多“跟手”的交互,比如 AppBar 滚动收起、FAB 随列表滚动隐藏/重现、底部弹层与列表的联动,都需要CoordinatorLayout作为承载者。
我之前做过一个详情页:顶部是折叠视差头部,中间是滚动内容,右下角是 FAB。如果用常规写法,要监听滚动事件再去改 FAB 透明度,代码又臭又长;改成CoordinatorLayout+AppBarLayout+CollapsingToolbarLayout后,通过app:layout_behavior和app:layout_scrollFlags几个属性就完成了,而且滑动动画是系统级跟手。
3.3 暗黑模式与动态颜色
从 Android 10 推出系统级深色模式后,控件的“上下文”又多了一个维度。MDC 组件库对深色模式支持得不错,只要你用主题属性引用颜色,切换到深色模式时大部分控件能自动适配。
如果你的应用要求自定义深浅色切换,我建议在values-night目录里重新覆盖同一套颜色资源,而不是为每个页面写两套布局。这样改动量最小,也符合 Material 官方推荐的“通过语义化颜色资产驱动主题切换”的思路。
4. 动效细节与手势反馈:把“规范”变成“体验”
很多开发者做到上一步就觉得界面“差不多能看”了,但真正精致的应用,往往胜在动效与反馈这些细微之处。
4.1 控件状态切换的动画时长
MDC 控件默认内置了状态切换动画,比如按钮从普通态变按压态时,高度与背景色都有一个渐变的过渡。如果你觉得默认动画不明显,可以通过attr/stateLayerColor和colorControlHighlight来微调涟漪颜色与透明度。
经验数值是:按压反馈的动画时长控制在 100ms~200ms 之间,太长会显得拖沓,太短则感知不到。比如rippleColor的透明度,正常态用 8%~12%,按压态用 16%~24%,视觉上刚刚好。
4.2 进场动效:列表与卡片
列表项的进场动画是最容易出效果的。我常用的是 RecyclerView 默认的DefaultItemAnimator,但如果你想让每个 item 之间有微小的“错峰”效果,可以自定义 Animator 为每个 item 设置不同延迟。
要注意一点:这种动画不要应用到所有界面。频繁进出的场景、列表项特别多的情况下,逐项动画会让用户反而感到“卡”。只在核心详情页、首屏卡片等地方使用,效果最好。
4.3 支持手势与触觉反馈
Material Design 的交互反馈不只是视觉变化,还有触觉。MDC 的按钮默认支持触觉反馈(Haptic Feedback),在 Android 10 及以上的设备上会有微弱的震动。如果你的业务有硬性需求,比如长按按钮触发特殊操作,可以结合View.performHapticFeedback做强化反馈,比只弹 Toast 要自然很多。
5. 常见问题与排查思路:我用血泪踩出来的坑
这部分记录我实际开发中的高频问题和排查过程,分享出来是为了帮你避开这些成本极高的坑。
5.1 控件换了个主题颜色还是不变
这个问题通常是因为你在老版本主题(如Theme.AppCompat)里使用 Material 控件。MDC 组件库的主题要求规定,必须用Theme.MaterialComponents或Theme.Material3家族作为基础主题,否�则控件的样式引用无法生效。
排查方案很简单:全局搜索parent="Theme.AppCompat,改成parent="Theme.MaterialComponents.Light.NoActionBar"或更高版本的基础主题,然后再看控件样式是否恢复。
5.2 TextInputLayout 输入框的底部指示线不见了
部分机型上会出现输入框底部指示线显示异常的问题,大多是因为给 EditText 单独设置了android:background。在 Material 设计体系里,输入框的下划线由TextInputLayout内部的BoxBackground控制,你手动设置背景会把这条线覆盖掉。
解决办法是删除 EditText 上的背景设置,改为使用app:boxBackgroundMode="outline"或app:boxBackgroundMode="filled",再把颜色交给主题去管。
5.3 阴影在部分设备上显示过重或没阴影
elevation阴影在不同硬件、不同 Android 版本上表现差异很大。某些国产 ROM 会关闭或弱化阴影效果,导致设计稿里预期的层级感出不来。
如果你对层级显示要求高,可以用outlineSpotShadowColor和outlineAmbientShadowColor微调阴影颜色,或者用描边+浅色面的方式来模拟层次。注意这种方式只在静态界面有效,动态高度变化仍然需要依靠立体阴影。
5.4 RecyclerView 刷新时卡片闪烁或状态丢失
如果你给卡片设置了checkable或checkedIcon,刷新列表时状态很容易被 RecyclerView 复用机制搞乱。根本原因是 item 复用时控件状态未重置。
我在项目里的统一处理是:在onBindViewHolder里强制重置状态,比如holder.binding.card.isChecked = false,再根据数据设置正确状态。千万不要依赖控件的默认状态,因为复用机制不会帮你“还原”默认。
6. 一点真正想说的话:控件的终点不是“用对”,而是“克制”
把所有 Material 控件都堆在页面上,并不能让应用更好看。我自己的体会是,刚开始接触这套体系时,看到什么控件都觉得“高级”,测出来页面上全是卡片、按钮、悬浮球,交互反馈又多又密。后来回头删掉一半元素,界面反而清爽了很多。
如果你所在的项目已经接近交付阶段,需要做界面统一性体检,我建议按这个顺序检查一遍:主题颜色是否有硬编码、按钮是否符合主次关系、文本输入框是否用原生错误提示、列表滚动与 FAB 是否联动、暗黑模式下是否有对比度异常。
这些细节不显眼,但用户能感知到。控件只是材料,设计意图才是建筑。希望这篇内容能让你在下次拿到设计稿时,不只是“找控件”,而是能自然地思考——这里为什么需要这个控件,它的状态该如何变化,它和周围的空间怎样建立联系。想清楚这些问题,做出来的东西就自带 Material 的质感了。
本文还有配套的精品资源,点击获取