一、FloatingActionButton 是什么?
FAB,全称 FloatingActionButton,是 Material Design 里一个标志性组件。说白了,就是一个悬浮在界面上的圆形按钮,通常用来触发 App 里最核心的那个操作。
我刚开始接触 Material Design 时,觉得 FAB 不就是个花哨的按钮吗?后来在项目里用多了才发现,它背后其实有一套完整的设计哲学——突出主要操作。比如邮件 App 里的「写邮件」、地图 App 里的「定位」、笔记 App 里的「新建笔记」。
嗯,这里要注意:FAB 不是装饰品。每个页面最多用一个 FAB,多了反而让用户困惑。
二、FAB 的基本使用
2.1 添加依赖
在 build.gradle 里加上 Material 库:
dependencies {
implementation 'com.google.android.material:material:1.9.0'
}
2.2 布局文件
直接在 XML 里声明就行:
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:src="@drawable/ic_add"
android:contentDescription="添加"
app:fabSize="normal" />
我个人习惯把 FAB 放在 CoordinatorLayout 里,这样它才能跟 Snackbar、AppBarLayout 这些组件联动。你想想看,如果 FAB 不在 CoordinatorLayout 里,Snackbar 弹出来时就会直接盖住 FAB,多难看。
2.3 常用属性
| 属性 | 说明 | 可选值 |
|---|---|---|
| app:fabSize | 按钮尺寸 | auto / normal / mini |
| app:backgroundTint | 背景颜色 | 颜色值 |
| app:rippleColor | 点击涟漪颜色 | 颜色值 |
| app:elevation | 阴影高度 | 数值(dp) |
| app:useCompatPadding | 是否使用兼容内边距 | true / false |
三、FAB 的行为与动画
3.1 点击事件
跟普通按钮一样,设置 OnClickListener:
fabAdd.setOnClickListener { view ->
// 执行主要操作
Snackbar.make(view, "已添加", Snackbar.LENGTH_SHORT).show()
}
3.2 显示与隐藏动画
FAB 自带缩放动画。调用 show() 和 hide() 就行:
fabAdd.hide() // 隐藏,带缩放动画
fabAdd.show() // 显示,带缩放动画
我在项目中遇到过一个问题:列表滚动时,FAB 应该隐藏,但用户快速滚动时动画会卡顿。后来发现是动画队列冲突了。解决办法是判断动画状态:
if (!fabAdd.isAnimating) {
fabAdd.hide()
}
3.3 自定义动画
如果你觉得默认动画不够炫,可以用 Transition 自定义:
val scale = ScaleTransition()
scale.duration = 300
fabAdd.transition = scale
fabAdd.show()
四、FAB 与 Snackbar 联动
这是 Material Design 里最经典的组合之一。Snackbar 弹出时,FAB 会自动上移,避免被遮挡。这个效果全靠 CoordinatorLayout 的 Behavior 机制实现。
4.1 核心原理
FAB 内部有一个默认的 Behavior——FloatingActionButton.Behavior。它会监听 CoordinatorLayout 里的子 View 变化。当 Snackbar 出现时,Behavior 会计算 Snackbar 的高度,然后让 FAB 向上平移同样的距离。
说白了,就是 CoordinatorLayout 在中间当「调度员」,Snackbar 通知它「我要出来了」,它再通知 FAB「你往上挪一挪」。
4.2 代码实现
布局结构必须是这样:
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 你的内容区域 -->
<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<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" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
然后在 Activity 里:
val fab = findViewById<FloatingActionButton>(R.id.fab)
fab.setOnClickListener { view ->
Snackbar.make(view, "操作成功", Snackbar.LENGTH_LONG)
.setAction("撤销") {
// 撤销操作
}
.show()
}
注意:Snackbar.make() 的第一个参数必须是 CoordinatorLayout 里的子 View。我习惯传 FAB 本身,这样 Snackbar 会显示在底部,FAB 自动上移。
4.3 避坑指南
我曾经踩过一个坑:FAB 没有放在 CoordinatorLayout 里,而是放在 RelativeLayout 里。结果 Snackbar 弹出来时,FAB 纹丝不动,直接被 Snackbar 盖住一半。用户点 FAB 时老是点到 Snackbar 上。
解决方案:确保 FAB 的父布局是 CoordinatorLayout,并且 FAB 的 layout_gravity 设置为 bottom|end。
五、FAB 的进阶用法
5.1 扩展 FAB(ExtendedFloatingActionButton)
有时候光一个图标不够直观,比如「新建」按钮,用户可能不知道是新建什么。这时候可以用 ExtendedFloatingActionButton,它带文字:
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/fab_extended"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:text="新建笔记"
android:icon="@drawable/ic_add" />
我个人习惯在 App 首次引导时用 ExtendedFAB,等用户熟悉了再缩成普通 FAB。这样既降低了学习成本,又保持了界面简洁。
5.2 多个 FAB 的展开动画
有些 App 会用一个主 FAB 展开多个子 FAB,比如 Gmail 的「写邮件」展开后还有「写便签」「写提醒」。实现方式是用动画控制子 FAB 的平移和透明度:
fun toggleFabMenu() {
if (isMenuOpen) {
// 收起
fabSub1.animate().translationY(0f).alpha(0f)
fabSub2.animate().translationY(0f).alpha(0f)
} else {
// 展开
fabSub1.animate().translationY(-100f).alpha(1f)
fabSub2.animate().translationY(-200f).alpha(1f)
}
isMenuOpen = !isMenuOpen
}
嗯,这里要注意:子 FAB 的点击区域要足够大,不然用户很难点中。我一般把子 FAB 的 layout_margin 设成 8dp 以上。
六、知识体系总览
下面这张图总结了 FAB 的核心知识点和它们之间的关系:
七、总结
FAB 看起来简单,但用好了能让 App 的交互体验提升一个档次。我总结几个要点:
- 位置固定:右下角,不要乱放
- 操作唯一:一个页面只放一个 FAB
- 联动必配:FAB + CoordinatorLayout + Snackbar 是铁三角
- 动画适度:不要为了炫技加太多动画,用户会晕
小技巧:如果你想让 FAB 在列表滚动时隐藏,可以用 RecyclerView 的 OnScrollListener 监听滚动方向,向下滚动时调用 fab.hide(),向上滚动时调用 fab.show()。这样用户体验会好很多。
好了,FAB 的内容就这些。你在项目里用 FAB 时遇到过什么奇怪的问题吗?欢迎交流。
公众号:蓝海资料掘金营,微信deep3321