如何在您的Flutter应用程序中添加SliverAppBar
什么是SliverAppBar?
在Flutter中,SliverAppBar是AppBar部件的继承者,它允许您创建浮动的应用栏效果。SliverAppBar在屏幕向上滚动时展开AppBar,向下滚动时折叠。
当用户向下滚动一个长的列表时,你也可以完全删除或隐藏AppBar。SliverAppBar有很多自定义选项,所以你可以根据你的需要来定制它。
如果你是一个视觉学习者,可以看看这个快速视频教程。
下面是让SliverAppBar启动和运行的最小代码。
return Scaffold(
//1
body: CustomScrollView(
slivers: <Widget>[
//2
SliverAppBar(
expandedHeight: 250.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('Goa', textScaleFactor: 1),
background: Image.asset(
'assets/images/beach.png',
fit: BoxFit.fill,
),
),
),
//3
SliverList(
delegate: SliverChildBuilderDelegate(
(_, int index) {
return ListTile(
leading: Container(
padding: EdgeInsets.all(8),
width: 100,
child: Placeholder()),
title: Text('Place ${index + 1}', textScaleFactor: 2),
);
},
childCount: 20,
),
),
],
),
);
要添加CustomScrollView,请将CustomScrollView
,放在Scaffold widget的body部分。这是用来同步AppBar和列表的滚动位置的。
有几个小部件可以被添加到CustomScrollView中,SliverAppBar就是其中之一。
SliverAppBar提供了普通AppBar小部件的所有功能,并增加了动画功能。flexibleSpace
,用于在AppBar展开时显示任何小部件。expandedHeight
,用于设置FlexibleSpaceBar这个小部件的高度。
SliverList显示项目的列表。我们不能使用普通的ListView类,因为CustomScrollView接受sliver类型的widget。
下面是输出结果。

海滩图片来源:vecteezy.com。
这里是代码如何转化为设计的。

自定义浮动行为
默认行为将在向下滚动时隐藏SliverAppBar,向上滚动时到达列表中的第一个项目时展开。然而,SliverAppBar有选项可以自定义这种行为。
SliverAppBar有三个重要的属性,即pinned
,snap
和floating
。设置这三个参数的组合可以使SliverAppBar按照你的需要工作。
让我们通过一个实际的例子来证明这些属性是如何工作的。
pinned: true,snap: false,floating: false:
只设置一个钉子的值为true
,当向下滚动时,SliverAppBar就会粘在顶部。当向上滚动时,SliverAppBar只在到达列表中的第一个项目时展开。

pinned: true,snap: true,floating: true:
当所有的参数都设置为true
,SliverAppBar在向下滚动时停留在顶部,向上滚动时完全展开,即使没有到达列表中的第一个项目。

pinned: true,snap: false,floating: true:
当只有snap值被设置为false
,SliverAppBar在向下滚动时保持在顶部。当我们向上滚动时,背景图片开始膨胀,并随着我们的滚动而停止。

pinned: false,snap: false,floating: true:
只将浮动值设置为true
,在向下滚动时隐藏SliverAppBar,当我们向上滚动时开始显示背景图片。

pinned: false,snap: true,floating: true:
如果你想让SliverAppBar在向下滚动时保持隐藏,而在向上滚动时显示完整的背景图片,即使是在列表中的第一个项目没有显示时。你可以只设置snap和floating为true
。

在SliverAppBar内添加AppBar
需要注意的是,SliverAppBar并不能完全替代正常的AppBar。在Flutter中编写应用程序的好处是,你可以混合和匹配小部件来创造新的东西。
例如,你可能会遇到这样的情况:你需要在SliverAppBar内显示一个包含搜索框的AppBar。
让我们看一个例子。下面是一个电子商务应用程序,当向下滚动时,横幅图片被隐藏,而搜索框仍然停留在顶部。

下面是如何做到这一点的。
Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
...
bottom: AppBar(
title: Container(
height: 45,
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
hintText: 'Enter a search term'),
),
),
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 2,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return ItemTile(index);
},
),
),
],
),
)
让我们来分解一下代码。首先,只要在SliverAppBar的bottom
属性中写一个普通的AppBar。该AppBar将包含TextField部件作为搜索项目的输入框。
项目的列表显示在SliverGrid中。由于我们使用了CutomScrollView,我们不能在这里使用普通的GridView。
用SliverAppBar添加TabBar
TabBar小部件用于显示不同类别的内容或用户可用的功能。在某些情况下,你可能想用SliverAppBar来显示TabBar。
让我们来看看如何添加TabBar并使其表现得像下面的例子。

Scaffold(
body: DefaultTabController(
length: 3,
child: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
pinned: false,
expandedHeight: 250.0,
flexibleSpace: FlexibleSpaceBar(
title: Text('Goa', textScaleFactor: 1),
background: Image.asset(
'assets/images/beach.png',
fit: BoxFit.fill,
),
stretchModes: [StretchMode.zoomBackground],
),
//collapsedHeight: 100,
),
SliverPersistentHeader(
delegate: MySliverPersistentHeaderDelegate(
TabBar(
tabs: [
Tab(icon: Icon(Icons.flight)),
Tab(icon: Icon(Icons.directions_transit)),
Tab(icon: Icon(Icons.directions_car)),
],
),
),
pinned: false,
),
];
},
body: TabBarView(
children: [
Icon(Icons.flight, size: 350),
Icon(Icons.directions_transit, size: 350),
Icon(Icons.directions_car, size: 350),
],
),
),
),
)
NestedScrollView部件被用来返回标题,作为SliverAppBar和SliverPersistentHeader部件的组合。SliverAppBar内部使用SliverPersistentHeader来实现收缩和增长的效果。你可以使用这个小部件来显示SliverAppBar下面的标签。
TabBarView在NestedScrollView widget的body
参数中给出。
下面是上面的代码如何转化为设计。

钉住TabBar
如果你仔细观察,当向下滚动时,TabBar是隐藏的。为了改善用户体验,在向下滚动时,你应该始终保持TabBar在顶部可见。
在SliverPersistentHeader中设置pinned
值为true
,将解决这个问题。
SliverPersistentHeader(
delegate: MySliverPersistentHeaderDelegate(
TabBar(
tabs: [
...
],
),
),
pinned: true,
)
下面是它的工作原理。

监听SliverAppBar的状态(展开或折叠
如果想要监听SliverAppBar的状态,以确定它是展开的还是折叠的,你可以使用返回的值来改变SliverAppBar的设置。例如,当它被展开时,你可以改变标题的文本颜色。
late ScrollController _scrollController;
//----------
@override
void initState() {
// TODO: implement initState
super.initState();
_scrollController = ScrollController()
..addListener(() {
setState(() {
_textColor = _isSliverAppBarExpanded ? Colors.white : Colors.blue;
});
});
}
//----------
bool get _isSliverAppBarExpanded {
return _scrollController.hasClients &&
_scrollController.offset > (200 - kToolbarHeight);
}
//----------
Scaffold(
body: CustomScrollView(
controller: _scrollController,
slivers: ...,
),
);
- ScrollController被创建并分配给CustomScrollView
- 监听器被添加到ScrollController中,以计算SliverAppBar是否被展开。
- 从监听器返回的值被用来设置标题的文本颜色。
下面是当SliverAppBar展开时改变标题 "Goa "颜色的输出。

结论
如果你已经走到了这一步,你应该具备了在你的Flutter应用程序中添加SliverAppBar的所有必要知识。
这个例子中使用的完整代码可以在GitHub上找到。