Material3 组件库:从 AppCompat 到现代 Material Design

说实话,Android 的 UI 框架演进,我一直觉得挺有意思的。从早期的 Holo 风格,到 Material Design 1.0,再到现在的 Material 3(简称 M3),每一次迭代都在解决实际问题。今天我们就来聊聊 Material3 组件库,以及它带来的那些新玩意儿。

我个人习惯把 Material3 看作是 Google 对「设计系统」的一次彻底重构。它不再只是换个颜色、改个圆角那么简单。M3 引入了动态颜色、新的组件规范,还有对自适应布局的深度支持。说白了,它想让你的 App 在不同设备上看起来都像「亲儿子」。

从 AppCompat 到 Material3:迁移路径

很多老项目还在用 AppCompat 主题。这没问题,AppCompat 依然稳定。但如果你想用上 M3 的新特性,比如动态颜色、SearchBar、BottomSheet 这些,就得迁移到 Material3。

迁移其实不复杂。你只需要做两件事:

  1. 把主题的 parent 从 Theme.MaterialComponents.DayNight 改成 Theme.Material3.DayNight
  2. 引入 M3 的依赖库
// build.gradle (app)
implementation 'com.google.android.material:material:1.12.0'

嗯,这里要注意。M3 的依赖库版本至少要到 1.9.0 以上,才能获得完整的动态颜色支持。我建议直接用 1.12.0,稳定且 bug 少。

⚠️ 注意: 如果你项目里用了自定义的 MaterialButton 样式,迁移后可能需要微调。M3 的按钮默认高度和圆角都变了。我曾经在一个老项目里直接替换主题,结果按钮全扁了……后来发现是 shapeAppearance 属性没适配。

主题切换与动态颜色:让 App 学会「看」壁纸

动态颜色是 M3 最让我兴奋的特性。它可以从用户的壁纸中提取主色、次色和中性色,然后自动生成一套完整的配色方案。你的 App 不需要写死颜色,系统帮你搞定。

实现起来很简单:

<!-- themes.xml -->
<style name="Theme.MyApp" parent="Theme.Material3.DayNight.NoActionBar">
    <item name="colorPrimary">@color/m3_dynamic_primary</item>
    <item name="colorSecondary">@color/m3_dynamic_secondary</item>
    <item name="colorTertiary">@color/m3_dynamic_tertiary</item>
</style>

然后在代码里,你不需要做任何额外处理。系统会自动读取壁纸颜色并应用到组件上。但有个前提:用户必须开启「动态颜色」开关(Android 12+)。

💡 小技巧: 如果你想在代码里获取动态颜色,可以用 DynamicColors.getColor(context, R.attr.colorPrimary)。我一般在自定义 View 里用这个,确保颜色和系统一致。

主题切换呢?M3 支持亮色/暗色主题自动切换。你只需要在 res/values-night 目录下放一份暗色主题的配置即可。系统会根据系统设置自动切换。

但如果你想要手动切换(比如 App 内设置),可以用 AppCompatDelegate.setDefaultNightMode()。我个人习惯把这个逻辑封装在 BaseActivity 里,这样所有页面统一管理。

TopAppBar 与 NavigationBar:适配 M3 新规范

TopAppBar 在 M3 里变化挺大的。它不再只是一个简单的标题栏,而是变成了一个可折叠、可交互的容器。M3 的 TopAppBar 有三种模式:

  • Small:和以前一样,显示标题和操作按钮
  • Medium:标题更大,适合作为页面主标题
  • Large:标题超大,配合滚动可以折叠成 Small

我个人最喜欢 Large 模式。它让页面看起来更有层次感。实现起来也不复杂:

<com.google.android.material.appbar.MaterialToolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    app:title="我的页面"
    app:titleCentered="false" />

如果你想要 Large 模式,需要配合 CollapsingToolbarLayout 使用。嗯,这里有个坑:Large 模式的标题默认是居左的,如果你想要居中,得自己写布局。我建议不要强行居中,M3 的设计规范就是居左,强行改反而奇怪。

NavigationBar 呢?M3 的 NavigationBar 就是以前的 BottomNavigationView。它现在支持三个或五个标签,而且有「活动指示器」动画。说白了,就是选中项会有一个小圆点或者高亮条。

适配很简单:

<com.google.android.material.navigation.NavigationBarView
    android:id="@+id/nav_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:menu="@menu/bottom_nav_menu" />

但要注意,M3 的 NavigationBar 默认高度比之前高了 8dp。如果你之前有自定义间距,可能需要重新调整。

Material3 中的新组件:SearchBar 与 BottomSheet

M3 引入了一些全新的组件,其中 SearchBar 和 BottomSheet 是我觉得最实用的。

SearchBar:搜索体验的现代化改造

SearchBar 不是一个简单的 EditText。它是一个可展开的搜索入口,点击后会弹出一个全屏的搜索界面(SearchView)。它支持语音输入、历史记录、搜索建议等。

用法:

<com.google.android.material.search.SearchBar
    android:id="@+id/search_bar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:hint="搜索..."
    app:menu="@menu/search_menu" />

然后在代码里,你需要把它和 SearchView 关联起来:

val searchBar = findViewById<SearchBar>(R.id.search_bar)
val searchView = findViewById<SearchView>(R.id.search_view)

searchBar.setOnClickListener {
    searchView.show()
}

searchView.addTransitionListener { _, _, state ->
    if (state == SearchView.TransitionState.SHOWN) {
        // 搜索界面已展开
    }
}

我曾经在一个电商项目里用 SearchBar 替换了原来的 EditText。用户体验提升很明显——搜索界面自带过渡动画,而且支持语音输入,用户反馈很好。

BottomSheet:更灵活的底部弹窗

M3 的 BottomSheet 有两种:Modal BottomSheet(模态)和 Persistent BottomSheet(持久)。Modal 是弹窗,需要用户主动关闭;Persistent 是固定在页面底部的面板,可以上下拖动。

Modal BottomSheet 的用法:

val bottomSheet = ModalBottomSheet(context)
val view = layoutInflater.inflate(R.layout.sheet_content, null)
bottomSheet.setContentView(view)
bottomSheet.show()

Persistent BottomSheet 则需要配合 CoordinatorLayout 使用:

<androidx.coordinatorlayout.widget.CoordinatorLayout ...>
    <com.google.android.material.bottomsheet.BottomSheetBehavior
        android:id="@+id/bottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        app:behavior_peekHeight="80dp"
        app:behavior_hideable="true" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

嗯,这里有个坑。Persistent BottomSheet 的 peekHeight 决定了它默认显示的高度。如果你设置得太小,用户可能看不到内容。我建议至少 80dp,配合一个明显的拖拽手柄。

知识体系总览

为了让你更直观地理解 M3 组件库的结构,我画了一张图:

Material3 组件库知识体系 Material3 组件库 主题切换与动态颜色 DynamicColors 自动配色 亮色/暗色主题自动切换 TopAppBar & NavigationBar Small / Medium / Large 模式 活动指示器动画 新组件:SearchBar & BottomSheet SearchBar + SearchView 联动 Modal / Persistent 两种模式

总结一下

Material3 不是简单的 UI 升级。它带来了动态颜色、新的组件规范,还有对自适应布局的深度支持。如果你还在用 AppCompat,我建议你尽快迁移。迁移成本不高,但用户体验的提升是实实在在的。

最后说一句:不要为了用 M3 而用 M3。如果你的 App 用户群体还在 Android 10 以下,动态颜色就用不了。这时候你可以考虑降级方案——用 M3 的组件,但颜色自己定义。灵活一点,总没错。

📌 核心要点:
  • 迁移到 M3 只需改主题 parent 和依赖版本
  • 动态颜色自动适配壁纸,但需要 Android 12+
  • TopAppBar 支持三种模式,Large 模式需要 CollapsingToolbarLayout
  • SearchBar 和 BottomSheet 是 M3 的亮点,值得优先使用

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