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 中重写 onCreateOptionsMenuonOptionsItemSelected 方法。

注意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 设置。我曾经见过有人把 srcbackground 搞混,结果图标显示不出来。

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 知识体系结构图

下面这张图展示了本章的核心知识点和它们之间的关系:

Material Design 核心组件知识体系 Material Design 核心概念 Toolbar / ActionBar 顶部导航栏,支持自定义菜单 NavigationView 侧滑菜单,配合 DrawerLayout FloatingActionButton 悬浮按钮,触发主要操作 Snackbar / Toast 消息提示,Snackbar 支持交互 核心原则:模拟物理世界,提供一致的用户体验

16.7 避坑指南

最后,分享几个我在项目中踩过的坑:

  1. Toolbar 标题不显示:检查是否调用了 setSupportActionBar(),以及主题是否使用了 NoActionBar 风格。
  2. NavigationView 菜单项不响应点击:确保在 Activity 中实现了 NavigationView.OnNavigationItemSelectedListener 接口。
  3. FAB 被 Snackbar 遮挡:把根布局换成 CoordinatorLayout,它会自动处理 FAB 的位移。
  4. Toast 在 Android 12 上显示异常:新版本对 Toast 的显示做了限制,建议改用 Snackbar。

嗯,这些坑说起来都是小问题,但排查起来真的很费时间。希望你能一次避开。


公众号:蓝海资料掘金营,微信deep3321