这是我参与更文挑战的第18天,活动详情查看: 更文挑战
上一篇我们聊了底部导航栏
BottomNavigationBar
的使用详解,这篇我们聊聊 FloatingActionButton 与 BottomAppBar的使用,为啥要放到一起呢?只有这两个 Widget 组合在一起才可以出效果,单独聊没有太大的价值,因为使用都比较简单。
比如这些奇怪的导航,我们要怎么实现?
| 凹凸菜单 | 圆角导航 | 波浪导航 |
|---|---|---|
|
|
|
|
FloatingActionButton
实现上面的效果前,我们先聊聊
FloatingActionButton
(中间蓝色加号按钮),然后再与下面的
BottomAppBar
结合即可
先看整体结构
Scaffold(
body:[bodyWidget],
// 这里设置悬浮按钮
floatingActionButton: FloatingActionButton(
// 设置一个➕按钮
child: Icon(Icons.add),
// 添加点击事件
onPressed: () {
一般我们使用它就是在 Scaffold 中设置即可,当然他是一个 Widget 我们在任何地方都可以使用他。
backgroundColor: Colors.orange foregroundColor: Colors.orange splashColor: Colors.orange 


elevation: 0 elevation: 6(默认) highlightElevation: 12 


mini: true shape: RoundedRectangleBorder shape: ContinuousRectangleBorder 


FloatingActionButton(
child: Icon(Icons.add),
// backgroundColor: Colors.orange,
// foregroundColor: Colors.orange,
// splashColor: Colors.orange,
// elevation: 6,
// highlightElevation: 12,
// mini: true,
// shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
// shape: ContinuousRectangleBorder(
// side: BorderSide(
// width: 4,
// color: Colors.orange,
// ),
// borderRadius: BorderRadius.circular(12),
// ),
// shape: BeveledRectangleBorder(
// side: BorderSide(
// width: 4,
// color: Colors.orange,
// ),
// borderRadius: BorderRadius.circular(12),
// ),
onPressed: () {
上面是写基本的设置的属性,有时我们还有一些特殊的需求,比如
你会发现除了刚才设置的 mini 和默认大小外,没有属性可以设置大小,那么我们就在外层包一层 SizedBox 即可。
SizedBox(
width: 80,
height: 80,
child: FloatingActionButton(...),
比如我们做上下排列的效果,那么我们只需要添加一个 Column 即可,里面放置多个 FloatingActionButton 即可
Column(
mainAxisSize: MainAxisSize.min,
children: [
FloatingActionButton(
child: Icon(Icons.ac_unit_rounded),
backgroundColor: Colors.orange,
onPressed: () {},
SizedBox(height: 10),
FloatingActionButton(
child: Icon(Icons.adb_sharp),
backgroundColor: Colors.green,
onPressed: () {},
SizedBox(height: 10),
FloatingActionButton(
child: Icon(Icons.more_horiz_outlined),
onPressed: () {},
FloatingActionButton 还有个 heroTag 属性我们没有聊,这个是干嘛用的呢?这个就是 Hero widget 的标签,如果此时我们设置点击跳转到一个新的页面,那么会报错,因为在 material 的设计规范里,每个屏幕只能有一个悬浮按钮,如果多个的话,在路由导航是就会出现标签冲突(不设置都是默认标签对象),解决版本就是设置不同的 heroTag 即可。
Column(
mainAxisSize: MainAxisSize.min,
children: [
FloatingActionButton(
child: Icon(Icons.ac_unit_rounded),
backgroundColor: Colors.orange,
// 设置 tag1
heroTag: 'tag1',
onPressed: () {},
SizedBox(height: 10),
FloatingActionButton(
child: Icon(Icons.adb_sharp),
backgroundColor: Colors.green,
// 设置 tag2
heroTag: 'tag2',
onPressed: () {},
SizedBox(height: 10),
FloatingActionButton(
child: Icon(Icons.more_horiz_outlined),
// 设置 tag3
heroTag: 'tag3',
onPressed: () {},

如上图我们可以通过 Scaffold 的 floatingActionButtonLocation 属性来设置 FloatingActionButton 的位置,为了更好的展示,我们增加一个 BottomAppBar 来帮助我们理解各个属性的调配
BottomAppBar
上一篇我们聊过 BottomNavigationBar ,这里我们将 bottomNavigationBar 属性改为 BottomAppBar ,因为 Flutter 中所有的控件都是 Widget
Scaffold(
// 设置位置,中心停靠
floatingActionButtonLocation:FloatingActionButtonLocation.centerDocked,
// 设置 BottomAppBar
bottomNavigationBar: BottomAppBar(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
TextButton.icon(
icon: Icon(Icons.home),
label: Text('首页'),
onPressed: () {},
SizedBox(),
TextButton.icon(
icon: Icon(Icons.people),
label: Text('我的'),
onPressed: () {},
非 mini
小表展示了各种位置效果,觉得有用记得点赞支持我哦
startFloat centerFloat endFloat 


startDocked centerDocked endDocked 


startTop centerTop endTop 


mini 类型
这个需要配合 FloatingActionButton 中的 mini 属性来使用,并且位置属性加了前缀 mini,如 FloatingActionButtonLocation.miniCenterDocked ,位置与上面是一致的。
区别在于 BottomAppBar 设置缺口 shape 的时候,缺口的半径不同
centerDocked miniCenterDocked 

多形状 Shape
在 Flutter 很多 Widget 都是可以设置 Shape 来自定义形状的,从输入框的边框线条到背景都是如此。
圆形缺口矩形
BottomAppBar(
/// 圆形缺口矩形
shape: CircularNotchedRectangle(),
child: [childWidget],
BottomAppBar(
/// 自动缺口形状
shape: AutomaticNotchedShape(
// 斜角矩形
BeveledRectangleBorder(
borderRadius: BorderRadius.circular(20),
child: [childWidget],
BottomAppBar(
/// 自动缺口形状
shape: AutomaticNotchedShape(
// 圆角矩形
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
child: [childWidget],
自定义形状
如果上面的一些效果也不能满足我们的需求,我们可以选择自定义 Shape,具体怎么自定义可以看下面的代码,当然如果你阅读 Flutter 的源码会更好。
BottomAppBar(
/// 自定义形状
shape: MyShape(),
child: [childWidget],
/// 自定义Shape
class MyShape extends NotchedShape {
@override
Path getOuterPath(Rect host, Rect? guest) {
var path = Path();
int wallCount = 10;
double step = host.width / wallCount;
double wall = host.height / 4;
for (var i = 0; i < wallCount; i++) {
// 上下起伏的锯齿状
path.relativeLineTo(step, i.isEven ? -wall : wall);
// 分别连接到右下角、左下角、闭合左上角
..lineTo(host.right, host.bottom)
..lineTo(host.left, host.bottom)
..close();
return path;
/// 自定义Shape
class MyShape extends NotchedShape {
@override
Path getOuterPath(Rect host, Rect? guest) {
var path = Path();
int wallCount = 10;
double step = host.width / wallCount;
double wall = host.height / 4;
for (var i = 0; i < wallCount; i++) {
// 圆角波浪
path.relativeArcToPoint(
Offset(step, i.isEven ? -wall : wall),
radius: Radius.circular(20),
// 分别连接到右下角、左下角、闭合左上角
..lineTo(host.right, host.bottom)
..lineTo(host.left, host.bottom)
..close();
return path;
基于 Flutter 🔥 最新版本
Flutter Widgets 仓库
FloatingActionButton (Flutter Widget of the Week)
Flutter-FloatingActionButton
Flutter-BottomAppBar
此文章已收录到下面👇 的专栏,可以直接关注
更多文章继续阅读|系列文章持续更新
👏 欢迎点赞➕收藏➕关注,有任何问题随时在下面👇评论,我会第一时间回复哦