16. Material Design 设计规范:从概念到实战
说实话,Material Design 刚出来那会儿,我第一反应是:「这不就是 Google 把纸片搬到了屏幕上吗?」后来真正做项目才发现,这套设计语言背后藏着很多细节。今天咱们就聊聊 Material Design 的核心概念,以及几个最常用的组件。
16.1 Material Design 核心概念
Material Design 是 Google 在 2014 年推出的设计语言。它的核心理念,说白了就是「模拟真实世界的物理规律」。你想想看,现实中的纸片有厚度、有阴影、有层次感,Material Design 把这些特性搬到了数字界面里。
我个人习惯把 Material Design 的核心概念总结为三点:
- 材质与深度:每个 UI 元素都像一张「纸片」,有厚度和阴影。阴影越深,元素离用户越近。
- 动效与反馈:点击按钮要有涟漪效果,切换页面要有过渡动画。这些动效不是花架子,而是给用户明确的反馈。
- 响应式布局:同一套设计,在手机、平板、电脑上都能自适应。说白了就是「一次设计,到处适配」。
核心要点:Material Design 不是死板的规则,而是一套「设计哲学」。你可以灵活运用,但不要违背物理直觉。
我在项目中遇到过一个问题:设计师给了一个很漂亮的阴影效果,但代码实现后发现阴影方向不对。后来查文档才发现,Material Design 的阴影方向默认是底部偏右,模拟的是「顶部光源」的效果。嗯,这个细节很容易被忽略。
16.2 Toolbar 与 ActionBar
ActionBar 是 Android 早期就有的顶部导航栏。Toolbar 是 Material Design 推出的替代方案。两者功能类似,但 Toolbar 更灵活。
为什么要用 Toolbar 替代 ActionBar?我举个例子:ActionBar 的位置是固定的,只能在屏幕顶部。而 Toolbar 可以放在任何位置,甚至嵌入到布局里。你想想看,这种灵活性有多重要。
16.2.1 基本用法
首先,在 build.gradle 中添加依赖:
implementation 'com.google.android.material:material:1.9.0'
然后在布局文件中使用 Toolbar:
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:title="我的应用"
app:titleTextColor="@android:color/white" />
在 Activity 中设置:
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
小技巧:如果你想让 Toolbar 支持返回按钮,可以这样写:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
16.2.2 自定义菜单
Toolbar 支持在右侧添加菜单项。在 res/menu 目录下创建菜单文件:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_search"
android:icon="@drawable/ic_search"
android:title="搜索"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_settings"
android:title="设置"
app:showAsAction="never" />
</menu>
然后在 Activity 中重写 onCreateOptionsMenu 和 onOptionsItemSelected 方法。
注意:app:showAsAction 属性控制菜单项是否显示在 Toolbar 上。如果设为 always,可能会因为空间不足导致显示不全。建议用 ifRoom。
16.3 NavigationView 侧滑菜单
侧滑菜单,也叫抽屉菜单,是 Material Design 中很常见的导航模式。NavigationView 配合 DrawerLayout 使用,能快速实现这个效果。
我记得第一次做侧滑菜单时,踩了一个坑:菜单项点击后没有反馈。后来发现是忘了设置 itemBackground 属性。嗯,这个细节很容易被新手忽略。
16.3.1 布局结构
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 主内容区域 -->
<FrameLayout
android:id="@+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- 侧滑菜单 -->
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="@menu/nav_menu" />
</androidx.drawerlayout.widget.DrawerLayout>
16.3.2 菜单项配置
在 res/menu 目录下创建 nav_menu.xml:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item
android:id="@+id/nav_home"
android:icon="@drawable/ic_home"
android:title="首页" />
<item
android:id="@+id/nav_profile"
android:icon="@drawable/ic_profile"
android:title="个人中心" />
<item
android:id="@+id/nav_settings"
android:icon="@drawable/ic_settings"
android:title="设置" />
</group>
</menu>
小技巧:NavigationView 支持添加头部布局。在 app:headerLayout="@layout/nav_header" 中指定即可。头部布局通常用来显示用户头像和昵称。
16.4 FloatingActionButton 悬浮按钮
FloatingActionButton(简称 FAB)是 Material Design 的标志性组件。它通常放在屏幕右下角,用来触发主要操作。
我个人习惯把 FAB 用在「添加」或「新建」这类高频操作上。比如在笔记应用里,点击 FAB 创建新笔记。你想想看,这种设计是不是很直观?
16.4.1 基本用法
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:src="@drawable/ic_add"
app:backgroundTint="@color/colorAccent" />
在代码中设置点击事件:
FloatingActionButton fab = findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 执行操作
}
});
注意:FAB 的 src 属性设置的是图标,不是背景。背景颜色通过 app:backgroundTint 设置。我曾经见过有人把 src 和 background 搞混,结果图标显示不出来。
16.4.2 扩展 FAB
Material Design 还支持扩展 FAB,也就是带文字的悬浮按钮。用法很简单:
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/extended_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="新建笔记"
android:icon="@drawable/ic_add" />
16.5 Snackbar 与 Toast
Snackbar 和 Toast 都是用来显示简短消息的组件。但两者有本质区别:
- Toast:轻量级提示,几秒后自动消失,不能交互。
- Snackbar:可以包含操作按钮,支持滑动关闭,更符合 Material Design 风格。
说白了,如果你只是想让用户知道「操作成功」,用 Toast 就够了。如果你想让用户「撤销」操作,那就用 Snackbar。
16.5.1 Toast 用法
Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show();
16.5.2 Snackbar 用法
Snackbar.make(view, "删除了一条记录", Snackbar.LENGTH_LONG)
.setAction("撤销", new View.OnClickListener() {
@Override
public void onClick(View v) {
// 执行撤销操作
}
})
.show();
小技巧:Snackbar 的 make() 方法第一个参数是 View,用来确定显示位置。通常传入 CoordinatorLayout,这样 Snackbar 会自动避开 FAB 等组件。
我在项目中遇到过一个问题:Snackbar 显示后,FAB 没有自动上移。后来发现是因为布局里没有用 CoordinatorLayout。嗯,这个坑踩过一次就记住了。
16.6 知识体系结构图
下面这张图展示了本章的核心知识点和它们之间的关系:
16.7 避坑指南
最后,分享几个我在项目中踩过的坑:
- Toolbar 标题不显示:检查是否调用了
setSupportActionBar(),以及主题是否使用了NoActionBar风格。 - NavigationView 菜单项不响应点击:确保在 Activity 中实现了
NavigationView.OnNavigationItemSelectedListener接口。 - FAB 被 Snackbar 遮挡:把根布局换成 CoordinatorLayout,它会自动处理 FAB 的位移。
- Toast 在 Android 12 上显示异常:新版本对 Toast 的显示做了限制,建议改用 Snackbar。
嗯,这些坑说起来都是小问题,但排查起来真的很费时间。希望你能一次避开。
公众号:蓝海资料掘金营,微信deep3321