- UI组件
- 移动开发
- 设计系统
【免费下载链接】material-components-android
[MAINTENANCE MODE] Modular and customizable Material Design UI components for Android
本指南以仓库文档 docs/components/Search.md 为核心,结合
com.google.android.material.search包下的真实源码与 Catalog 示例,系统讲解 Material 3 Search 组件(SearchBar与SearchView)的结构、属性、M3 Expressive 新特性、代码集成与滚动行为定制。读完本文,你将能够在一个 Android 应用中完整落地「搜索栏 + 全屏搜索视图」的组合体验,并掌握包含式动画、预测性返回、无障碍支持等进阶配置。
一、什么是 Search 组件
Search(搜索)是一种导航模式,允许用户在应用中快速查找信息:用户在搜索栏(search bar)或搜索视图(search view)的文本框中输入查询,随后看到相关结果。Material Components for Android 将这一模式封装为两个协同工作的组件:
- SearchBar:位于屏幕顶部的常驻、醒目的搜索输入区域,用于承载搜索入口。
- SearchView:全屏模态界面,通常由点击搜索图标或
SearchBar触发打开,用于输入查询、展示历史/建议/结果。
从源码结构看,这两个组件都位于 lib/java/com/google/android/material/search 包内,核心实现为SearchBar.java(public class SearchBar extends Toolbar,见 SearchBar.java)与SearchView.java(public class SearchView extends FrameLayout implements CoordinatorLayout.AttachedBehavior, MaterialBackHandler,见 SearchView.java),动画逻辑由 SearchBarAnimationHelper.java 和 SearchViewAnimationHelper.java 承载。
二、组件解剖(Anatomy)
SearchBar 结构
SearchBar由以下部分组成:
- Container(容器)
- Leading icon button(前导图标按钮,默认为放大镜)
- Supporting text(辅助文本,即 hint 提示)
- Avatar 或 trailing icon(尾部头像或图标,可选)
SearchView 结构
SearchView由以下部分组成:
- Container(容器)
- Header(头部区域)
- Leading icon button(前导图标按钮,默认为返回箭头)
- Supporting text(辅助文本)
- Trailing icon button(尾部图标按钮,含清除按钮)
- Input text(输入文本
EditText) - Divider(分隔线)
SearchView在源码中通过 mtrl_search_view.xml 布局将这些元素组装起来,并在构造函数中逐一绑定(scrim、rootView、toolbar、editText、clearButton、divider等,见 SearchView.java)。注意SearchView重写了addView,所有以 XML 或代码方式添加的子 View 都会被放入内容容器contentContainer,这也是它能够内嵌搜索建议、结果列表的原因。
三、添加依赖与版本要求
Material Search 组件在1.8.0版本引入,使用前需确保依赖com.google.android.material:material:1.8.0或更高版本。完整的环境搭建步骤(Gradle 依赖、主题继承等)见仓库的 docs/getting-started.md。
四、M3 Expressive 更新(1.13.0+ 风格)
M3 Expressive 为搜索组件带来了一批外观与行为更新,仓库中的主题样式定义于 lib/java/com/google/android/material/search/res/values/styles.xml。
SearchBar 更新
- 新增 Centered Search Text 属性:支持文本居中显示。
- 新增 Maximum Width:限制搜索栏最大宽度。
- 新增 Lift on Scroll Color 属性:滚动抬升时的颜色。
- Padding 与 inset 更新:边距与系统栏内边距调整。
SearchBar的默认样式为:
<item name="materialSearchBarStyle">@style/Widget.Material3Expressive.SearchBar</item>也可以显式使用居中文本样式:
<item name="materialSearchBarStyle">@style/Widget.Material3Expressive.SearchBar.CenteredText</item>推荐布局:SearchBar 放入 AppBarLayout
Expressive 阶段推荐的展示方式是让SearchBar位于AppBarLayout内部,构成 "AppBar with Search"。你只需在AppBarLayout上指定主题:
<item name="materialSearchViewStyle">@style/Widget.Material3Expressive.SearchView.AppBarWithSearch</item>同时在AppBarLayout上应用android:theme="ThemeOverlay.Material3Expressive.AppBarWithSearch",即可自动为AppBarLayout与SearchBar设置样式。该主题覆盖层下SearchBar的默认样式为居中文本配置;若想使用起始对齐文本,需在SearchBar上显式设置@style/Widget.Material3Expressive.SearchBar.AppBarWithSearch。
SearchBar 与 MaterialToolbar 搭配(迁移路径)
新的 AppBar with Search 配置把图标从SearchBar内部移到了AppBarLayout中,客户端需要自己添加MaterialButton来替代这些图标。对于存量代码,官方提供了一条更平滑的迁移路径:把SearchBar包进MaterialToolbar,将前导/尾部图标设置到MaterialToolbar上,输入方式保持不变。示例:
<com.google.android.material.appbar.AppBarLayout android:id="@+id/app_bar_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" app:materialThemeOverlay="@style/ThemeOverlay.Material3Expressive.AppBarWithSearch" app:statusBarForeground="?attr/colorSurface"> <com.google.android.material.appbar.MaterialToolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" app:navigationIcon="@drawable/ic_home_checkable_24px" app:layout_scrollFlags="enterAlways|scroll|snap" app:navigationContentDescription="@string/home_icon_description" app:menu="@menu/search_menu"> <com.google.android.material.search.SearchBar android:id="@+id/search_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:hint="@string/searchbar_hint"> </com.google.android.material.search.SearchBar> </com.google.android.material.appbar.MaterialToolbar> </com.google.android.material.appbar.AppBarLayout>包含式(Contained)SearchView 样式
当SearchBar按上述方式位于AppBarLayout内时,可启用新的包含式SearchView样式——SearchBar在展开动画中会视觉上持续存在于SearchView内部,形成更连贯、更具表现力的体验。在主题中同时设置materialSearchViewStyle即可开启:
<item name="materialSearchViewStyle">@style/Widget.Material3Expressive.SearchView.AppBarWithSearch</item>注意:包含式SearchView的 "bouncy"(弹性)动画只在 Expressive 主题(如Theme.Material3Expressive.*)下可用;基础 M3 主题(Theme.Material3.*)虽然支持包含式视觉样式,但SearchBar展开会退化为线性运动。
SearchBar 图标动画
包含式展开过程中,SearchBar的兄弟视图(如图标按钮)会被动画移出屏幕以腾出空间:
若
SearchBar是Toolbar的直接子 View,导航按钮与菜单操作视图会自动被当作兄弟视图处理。其他场景需显式声明兄弟视图,可通过 XML 属性:
app:startSiblingViewIdapp:endSiblingViewId
或编程式 API:
SearchBar#setStartSiblingViewId(id)SearchBar#setEndSiblingViewId(id)
注意每侧只能指定一个 ID;如需同时动画多个图标,请将它们包裹进同一个
ViewGroup(如LinearLayout),再传入该容器的 ID。对应属性在 attrs.xml 中声明。
五、关键属性(Key Properties)
SearchBar 属性
| 元素 | 属性 | 相关方法 | 默认值 |
|---|---|---|---|
| 最大宽度 | android:maxWidth | setMaxWidthgetMaxWidth | -1(未设置) |
| 自适应最大宽度开关 | app:adaptiveMaxWidthEnabled | -- | false |
| 最小高度 | android:minHeight | setMinHeightgetMinHeight | @dimen/m3_searchbar_height |
| 搜索文本外观 | android:textAppearance | setTextAppearancegetTextAppearance | @style/TextAppearance.Material3.SearchBar |
| 搜索文本 | android:text | setTextgetText | null |
| 搜索提示 | android:hint | setHintgetHint | null |
| 搜索文本居中 | app:textCentered | setTextCenteredgetTextCentered | false |
| 颜色 | app:backgroundTint | -- | ?attr/colorSurfaceContainerHigh |
| 滚动抬升 | app:liftOnScroll | -- | false |
| 抬升颜色 | app:liftOnScrollColor | -- | ?attr/colorSurfaceContainerHighest |
| 默认边距开关 | app:defaultMarginsEnabled | -- | true |
| 导航图标开关 | app:hideNavigationIcon | -- | false |
| 进入 SearchView 时动画移出的起始兄弟视图 | app:startSiblingViewId | setStartSiblingViewIdgetStartSiblingViewId | -1(未设置) |
| 进入 SearchView 时动画移出的结束兄弟视图 | app:endSiblingViewId | setEndSiblingViewIdgetEndSiblingViewId | -1(未设置) |
除文档中的属性外,从 attrs.xml 的SearchBarstyleable 还可以看到:elevation(阴影高度)、defaultScrollFlagsEnabled(默认 AppBarLayout 滚动标志)、forceDefaultNavigationOnClickListener(强制默认导航点击监听,供将SearchBar设为 ActionBar 时使用)、tintNavigationIcon/navigationIconTint(导航图标着色)、strokeColor/strokeWidth(描边)等。默认高度定义于 dimens.xml:m3_searchbar_height引用m3_comp_search_bar_container_height令牌。
SearchView 属性
| 元素 | 属性 | 相关方法 | 默认值 |
|---|---|---|---|
| 搜索文本外观 | android:textAppearance | setTextAppearancegetTextAppearance | @style/TextAppearance.Material3.SearchBar |
| 搜索文本 | android:text | setTextgetText | null |
| 搜索提示 | android:hint | setHintgetHint | null |
| 颜色 | app:backgroundTint | -- | ?attr/colorSurfaceContainerHigh |
| 导航图标开关 | app:hideNavigationIcon | -- | true |
| DrawerArrowDrawable 开关 | app:useDrawerArrowDrawable | -- | false |
| 软键盘自动弹出开关 | app:autoShowKeyboard | setAutoShowKeyboard | true |
| 分隔线开关 | app:dividerVisible | -- | true |
SearchViewstyleable 还包含searchPrefixText(搜索前缀文本)、animateNavigationIcon/animateMenuItems(是否将导航图标/菜单项从SearchBar动画过渡到SearchView,默认均为true)、headerLayout(头部布局)、backHandlingEnabled(自动返回处理,默认true)、containedAnimationEnabled(包含式展开动画开关,默认false),见 attrs.xml。
样式速查
| 元素 | 样式 | 主题属性 |
|---|---|---|
| SearchBar 默认样式 | Widget.Material3.SearchBar | ?attr/materialSearchBarStyle |
| Expressive SearchBar 默认样式 | Widget.Material3Expressive.SearchBar | ?attr/materialSearchBarStyle |
| Expressive SearchBar 居中文本样式 | Widget.Material3Expressive.SearchBar.CenteredText | ?attr/materialSearchBarStyle |
| SearchView 默认样式 | Widget.Material3.SearchView | ?attr/materialSearchViewStyle |
| SearchView Toolbar 样式 | Widget.Material3.SearchView.Toolbar | ?attr/materialSearchViewToolbarStyle |
| SearchView Toolbar 高度 | @dimen/m3_searchview_height | ?attr/materialSearchViewToolbarHeight |
| Expressive SearchView 默认样式 | Widget.Material3Expressive.SearchView | ?attr/materialSearchViewStyle |
| Expressive SearchView Toolbar 样式 | Widget.Material3Expressive.SearchView.Toolbar | ?attr/materialSearchViewToolbarStyle |
| Expressive SearchView 包含式样式 | Widget.Material3Expressive.SearchView.AppBarWithSearch | ?attr/materialSearchViewStyle |
| Expressive SearchView Toolbar 包含式样式 | Widget.Material3Expressive.SearchView.Toolbar.AppBarWithSearch | ?attr/materialSearchViewToolbarStyle |
| Expressive Toolbar 包含式高度 | @dimen/m3e_searchview_appbarwithsearch_toolbar_height | ?attr/materialSearchViewToolbarHeight |
六、代码实现
1. 添加 SearchBar
SearchBar本质上是继承Toolbar的浮动搜索输入框,因此天然支持导航图标、菜单项以及其他所有ToolbarAPI;同时内置 hintTextView,并支持嵌套一个居中的品牌元素。使用方式:
searchBar.inflateMenu(R.menu.searchbar_menu); searchBar.setOnMenuItemClickListener( menuItem -> { // Handle menuItem click. return true; });由于SearchBar extends Toolbar(源码见 SearchBar.java),你也可以通过AppCompatActivity#setSupportActionBar将其设为ActionBar,并重写onCreateOptionsMenu填充菜单。但需要注意:若使用默认的放大镜navigationIcon,可能需要设置app:forceDefaultNavigationOnClickListener="true",避免因 Activity 的ActionBar流程把搜索图标当作返回按钮。
限制:SearchBar为了在各 App 间提供一致的视觉,不支持通过android:background设置自定义背景。
2. 添加 SearchView
SearchView提供全屏搜索视图,可展示返回导航、搜索提示与文本、菜单项以及搜索建议与结果,并内置一个随输入内容自动显示/隐藏的清除文本按钮。配置菜单:
searchView.inflateMenu(R.menu.search_view_menu); searchView.setOnMenuItemClickListener( menuItem -> { // Handle menuItem click. return true; });SearchView通过getEditText()暴露主EditText,可以套用所有传统EditTextAPI(setText()、addTextChangedListener()等)。下面的例子把搜索文本回填到SearchBar,并在用户按回车结束时隐藏SearchView:
searchView .getEditText() .setOnEditorActionListener( (v, actionId, event) -> { searchBar.setText(searchView.getText()); searchView.hide(); return false; });3. 无障碍(Accessibility)
- 应通过
android:contentDescription属性或setContentDescription方法为SearchBar/SearchView设置内容描述,方便 TalkBack 等屏幕阅读器播报其用途与动作;组件内的文本会自动提供给无障碍服务,通常无需额外标签。 SearchView显示时会自动把未嵌套在其中的兄弟视图标记为对无障碍不重要,隐藏时恢复原值。若在SearchView打开期间改动其根视图层级(例如直接移除SearchView),必须先行调用setModalForAccessibility(false)恢复原始无障碍值——因为此时hide()永远不会被调用(源码逻辑见 SearchView.java 及onDetachedFromWindow)。
4. 过渡监听器
若需要在SearchView动画状态切换时获得回调,可通过SearchView#addTransitionListener注册监听:
searchView.addTransitionListener( (searchView, previousState, newState) -> { if (newState == TransitionState.SHOWING) { // Handle search view opened. } });TransitionState枚举定义于 SearchView.java,包含HIDING、HIDDEN、SHOWING、SHOWN四种状态;SearchView内部以currentTransitionState跟踪当前状态,并通过isShowing()、getCurrentTransitionState()对外暴露。
5. 预测性返回(Predictive Back)
当SearchView与SearchBar按上述方式关联后,组件自动支持预测性返回(SearchView实现了MaterialBackHandler,见 SearchView.java,通过MaterialBackOrchestrator注册startBackProgress/updateBackProgress/handleBackInvoked回调)。应用侧除预测性返回的通用前置条件外,无需额外集成。通用迁移步骤见 docs/foundations/PredictiveBack.md。
七、自定义行为与场景
1. 展开 / 收起动画
SearchBar+SearchView组合最大的优势是免费获得展开与收起动画:点击SearchBar展开SearchView,返回时收起。如果单独使用SearchView(无SearchBar),则显示/隐藏退化为滑入滑出过渡。
2. 软键盘输入模式
使用SearchBar+SearchView时推荐windowSoftInputMode为adjustNothing,原因有二:
adjustResize会在键盘弹出时调整屏幕尺寸,容易造成展开/收起动画的卡顿。SearchView虽然会通过错峰(staggering)调度键盘与动画来缓解,但首选仍是adjustNothing,让键盘立即显示/隐藏。- 搜索场景下重排屏幕通常无益:用户要么继续输入查看更多结果,要么开始滚动——此时
SearchView会自动收起键盘以露出更多内容。
SearchView首次渲染时会从Window读取软输入模式;若在运行时动态修改了输入模式,务必同步调用SearchView#setSoftInputMode让组件调整行为。若不想在显示时自动弹出键盘,设置app:autoShowKeyboard="false"即可。
3. 半透明状态栏
SearchBar与SearchView均支持半透明状态栏:
- 防止
SearchBar被半透明状态栏遮挡:将其包裹在设置了android:fitsSystemWindows="true"的FrameLayout中。 - 不要在
SearchView上设置android:fitsSystemWindows。当使用FLAG_TRANSLUCENT_STATUS(android:windowTranslucentStatus)或FLAG_LAYOUT_NO_LIMITS时,SearchView会自动添加额外的 spacer surface 填充半透明状态栏下方的空间(源码中对应statusBarSpacer字段与 inset 监听逻辑,见 SearchView.java)。
4. 菜单到返回箭头的动画
若SearchBar与NavigationDrawer搭配使用,可在SearchView上设置app:useDrawerArrowDrawable="true",开启 "hamburger" 菜单到返回箭头的图标动画,动画在SearchView展开/收起时播放(源码中通过DrawerArrowDrawable实现,见 SearchView.java)。
5. 搜索前缀(Search Prefix)
如需在主搜索EditText前显示固定前缀文本,使用app:searchPrefixText属性。例如设置app:searchPrefixText="To:"会在输入框前显示固定标签 "To:"。此模式下通常配合app:hideNavigationIcon="true"隐藏返回按钮以减少杂乱(导航可由 SearchView 外部处理)。
6. 搜索历史、建议与结果
SearchView是 ViewGroup 组件,可以在其内部嵌套内容,例如:
- 首次展开时的搜索历史
- 输入过程中的搜索建议
- 提交搜索后的结果列表
<com.google.android.material.search.SearchView android:layout_width="match_parent" android:layout_height="match_parent" android:hint="@string/searchbar_hint" app:layout_anchor="@id/search_bar"> <!-- Search suggestions/results go here (ScrollView, RecyclerView, etc.). --> </com.google.android.material.search.SearchView>在源码中这些内容会被放进contentContainer(见 SearchView.java 的addView重写)。仓库 Catalog 的 SearchFragment.java 与 SearchRecyclerDemoActivity.java 是完整的参考实现。
7. 滚动行为三种模式
SearchBar支持三种滚动形态:固定、滚动消失、滚动抬升。
固定模式(Fixed)
将SearchBar置于布局内容顶部,不设置任何滚动行为或AppBarLayout,内容在下方滚动而SearchBar保持固定。
滚动消失模式(Scroll-away)
使用顶层CoordinatorLayout,把SearchBar放入AppBarLayout,并将AppBarLayout放在滚动视图(通常是RecyclerView或NestedScrollView)之后,同时在滚动视图上设置:
app:layout_behavior="@string/searchbar_scrolling_view_behavior"该行为(searchbar_scrolling_view_behavior定义于 strings.xml,对应SearchBar的Behavior)会使AppBarLayout透明、无阴影,并调整滚动子视图,让SearchBar悬浮覆盖在内容之上。若应用是 edge-to-edge 布局,建议给AppBarLayout添加app:statusBarForeground="?attr/colorSurface",避免滚动时SearchBar与状态栏内容重叠。
滚动抬升模式(Lift on Scroll)
同样使用顶层CoordinatorLayout+AppBarLayout,但在滚动视图上设置:
app:layout_behavior="@string/appbar_scrolling_view_behavior"并在SearchBar上设置:
app:liftOnScroll="true" app:liftOnScrollColor="?attr/colorSurfaceContainerHighest"这样当AppBarLayout滚动抬升时,SearchBar会改变颜色以凸显层次。
8. 综合示例:Scroll-away 模式完整布局
<androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- NestedScrollingChild goes here (NestedScrollView, RecyclerView, etc.). --> <androidx.core.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/searchbar_scrolling_view_behavior"> <!-- Screen content goes here. --> </androidx.core.widget.NestedScrollView> <com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <com.google.android.material.search.SearchBar android:id="@+id/search_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/searchbar_hint" /> </com.google.android.material.appbar.AppBarLayout> <com.google.android.material.search.SearchView android:layout_width="match_parent" android:layout_height="match_parent" android:hint="@string/searchbar_hint" app:layout_anchor="@id/search_bar"> <!-- Search suggestions/results go here (ScrollView, RecyclerView, etc.). --> </com.google.android.material.search.SearchView> </androidx.coordinatorlayout.widget.CoordinatorLayout>把SearchBar与SearchView放在同一个CoordinatorLayout中并通过app:layout_anchor关联,二者会自动完成接线:点击SearchBar显示SearchView,并具备展开/收起动画(SearchView实现了CoordinatorLayout.AttachedBehavior,见 SearchView.java)。如果无法使用CoordinatorLayout,可调用SearchView#setUpWithSearchBar达到相同效果。
Lift on scroll 模式的完整布局与上面类似,仅需将滚动视图的 behavior 改为@string/appbar_scrolling_view_behavior,并在SearchBar上增加app:liftOnScroll与app:liftOnScrollColor。
9. Toolbar 过渡(上下文多选等场景)
SearchBar还支持与Toolbar之间的双向过渡,例如上下文多选流程。过渡以展开/收起动画实现,分别通过SearchBar#expand与SearchBar#collapse触发(见 SearchBar.java);若同时使用AppBarLayout,可将AppBarLayout引用传入这两个方法,使动画考虑其可见性与偏移。最后,在返回键处理逻辑中加入以下代码,让用户按系统返回键时把上下文Toolbar收回到SearchBar:
if (searchBar.collapse(contextualToolbar, appBarLayout)) { // Clear selection. return; }八、仓库内的参考实现
- 组件源码:lib/java/com/google/android/material/search(
SearchBar.java、SearchView.java及两个动画 Helper) - 资源定义:attrs.xml、styles.xml、dimens.xml
- 布局模板:mtrl_search_bar.xml、mtrl_search_view.xml
- Catalog 示例:catalog/java/io/material/catalog/search,包括
SearchFragment、SearchRecyclerDemoActivity、SearchBarWithAppBarIconsDemoActivity(AppBar with Search 的图标外置示例)以及复用的 SearchDemoUtils.java - 主题样式参考:lib/java/com/google/android/material/search/res/values/styles.xml 中的
ThemeOverlay.Material3Expressive.AppBarWithSearch相关定义
通过组合上述属性、动画与滚动行为,你可以在应用中快速构建出一套符合 Material 3 规范的完整搜索体验,并获得与系统级搜索一致的交互质感。
- UI组件
- 移动开发
- 设计系统
【免费下载链接】material-components-android
[MAINTENANCE MODE] Modular and customizable Material Design UI components for Android
相关推荐
**Material Components for Android 指南**
Material Components for Android 指南 项目介绍 Material Components for Android MDC Andr
UI组件移动开发设计系统Material Components for iOS布局组件全解析:FlexibleHeader与AppBar实战指南
Material Components for iOS布局组件全解析:FlexibleHeader与AppBar实战指南 Material Components
原生移动Material Components for Android Dialog 完整指南:从 MaterialAlertDialogBuilder 到 Material 3 主题定制
Material Components for Android Dialog 完整指南:从 MaterialAlertDialogBuilder 到 Mater
UI组件移动开发设计系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考