为了方便用户查看列表,你可能希望在用户向下滚动列表时隐藏 app bar,尤其在你的 app bar 特别高,导致它占据了很多竖向空间的时候。

一般情况下,你可以通过给 Scaffold 组件设置一个 appBar 属性来创建一个 app bar。这个 app bar 会始终固定在 Scaffold 组件的 body 上方。

把 app bar 从 Scaffold 组件挪到一个 CustomScrollView 里,可以让你创建一个随着你滑动 CustomScrollView 里列表的同时在屏幕外自动随之滚动的 app bar。

下面这篇教程将介绍如何通过 CustomScrollView 来生成一个带有随着用户滑动列表同时会在屏幕外随之滚动的 app bar 的列表。

步骤

  • 创建一个 CustomScrollView

  • 通过 SliverAppBar 来添加一个浮动的 app bar

  • 通过 SliverList 来添加列表

1. 创建一个 CustomScrollView

要创建一个浮动的 app bar,你需要将 app bar 放在一个包含列表的 CustomScrollView 里,这会同步 app bar 和列表的滚动位置。你可以把 CustomScrollView 组件当成一个可以让你把不同类型的可滚动列表和组件混合匹配在一起的 ListView

可以放在 CustomScrollView 里的可滚动列表和组件我们称之为 slivers。有几种类型的 slivers,比如 SliverListSliverGridListSliverAppBar!实际上,ListViewGridView 组件底层使用的就是 SliverListSliverGrid

以下例子演示了创建一个包含 SliverAppBarSliverListCustomScrollView。另外你需要删除你之前可能设置在 Scaffold 组件上的 app bar!

  1. Scaffold(
  2. // 不需要设置 appBar 属性,只需要 body!(No appBar property provided, only the body!)
  3. body: CustomScrollView(
  4. // 下一步我们将在列表里把 app bar 作为一个 slivers 添加进去(Add the app bar and list of items as slivers in the next steps)
  5. slivers: <Widget>[]
  6. ),
  7. );

2. 使用 SliverAppBar 来添加一个浮动的 app bar

接下来为 CustomScrollView 添加一个 app bar。Flutter 提供开箱即用的 SliverAppBar 组件,与普通的 AppBar 组件非常相似,你可以使用 SliverAppBar 来显示标题、标签、图像等内容。

同时,SliverAppBar 组件也提供一种创建 “浮动” app bar 的能力,当用户向下滚动列表时,app bar 会随之在屏幕外滚动。此外,你可以配置 SliverAppBar 在用户滚动时缩小或展开。

要达到这个效果:

  • 先创建一个只显示标题的 app bar

  • floating 属性设为 true。这使用户在向上滚动列表时能快速显示 app bar。

  • 添加一个 flexibleSpace 组件,这个组件将填充可用的 expandedHeight

  1. CustomScrollView(
  2. slivers: <Widget>[
  3. SliverAppBar(
  4. title: Text('Floating app bar'),
  5. // 允许用户在开始向上滚动列表时显示 app bar(Allows the user to reveal the app bar if they begin scrolling back up the list of items)
  6. floating: true,
  7. // 用一个占位组件来显示收缩的范围(Display a placeholder Widget to visualize the shrinking size)
  8. flexibleSpace: Placeholder(),
  9. // 使 SliverAppBar 的初始高度大于正常高度(Make the initial height of the SliverAppBar larger than normal)
  10. expandedHeight: 200,
  11. ),
  12. ],
  13. );

小提示:Play around with the various properties you can pass to the SliverAppBarWidgetand use hot reload to see the results. For example, you can use an ImageWidget for the flexibleSpace property to create a background image thatshrinks in size as it’s scrolled offscreen.

试试 SliverAppBar 支持的各种属性,并使用热重载来查看结果。例如,你可以给 flexibleSpace 提供一个 Image 组件来创建一个背景图像,当它在屏幕外滚动时会缩小尺寸。

3. 使用 SliverList 来添加一个列表

现在你已经创建好一个 app bar,接下来应该给 CustomScrollView 添加一个列表。你有两种选择:用 SliverList 或用 SliverGrid。如果你需要一个一个往下排地显示列表中的内容,应该用 SliverList 组件。如果需要网格状地显示列表中的内容,应该用 SliverGrid 组件。

SliverListSliverGrid 组件都需要一个必要参数:SliverChildDelegate。虽然听起来很花哨,但它只是用来给列表组件 SliverListSliverGrid 提供一个代理。例如,SliverChildBuilderDelegate 允许你创建一组可以在滚动时懒加载的列表项,就和 ListView.builder 组件差不多。

  1. // Create a SliverList
  2. // 创建一个 SliverList
  3. SliverList(
  4. // 用代理在列表滚动的时候加载列表项(That uses a delegate to build items as they're scrolled on screen. )
  5. delegate: SliverChildBuilderDelegate(
  6. // 构造函数返回一个展示当前列表项序号的 ListTile(The builder function returns a ListTile with a title that displays the index of the current item)
  7. (context, index) => ListTile(title: Text('Item #$index')),
  8. // 展示 1000 个列表项(Builds 1000 ListTiles)
  9. childCount: 1000,
  10. ),
  11. )

完整示例

  1. import 'package:flutter/foundation.dart';
  2. import 'package:flutter/material.dart';
  3. void main() => runApp(MyApp());
  4. class MyApp extends StatelessWidget {
  5. MyApp({Key key}) : super(key: key);
  6. @override
  7. Widget build(BuildContext context) {
  8. final title = 'Floating App Bar';
  9. return MaterialApp(
  10. title: title,
  11. home: Scaffold(
  12. // No appbar provided to the Scaffold, only a body with a
  13. // CustomScrollView
  14. body: CustomScrollView(
  15. slivers: <Widget>[
  16. // Add the app bar to the CustomScrollView
  17. SliverAppBar(
  18. // Provide a standard title
  19. title: Text(title),
  20. // Allows the user to reveal the app bar if they begin scrolling
  21. // back up the list of items
  22. floating: true,
  23. // Display a placeholder Widget to visualize the shrinking size
  24. flexibleSpace: Placeholder(),
  25. // Make the initial height of the SliverAppBar larger than normal
  26. expandedHeight: 200,
  27. ),
  28. // Next, create a SliverList
  29. SliverList(
  30. // Use a delegate to build items as they're scrolled on screen.
  31. delegate: SliverChildBuilderDelegate(
  32. // The builder function returns a ListTile with a title that
  33. // displays the index of the current item
  34. (context, index) => ListTile(title: Text('Item #$index')),
  35. // Builds 1000 ListTiles
  36. childCount: 1000,
  37. ),
  38. ),
  39. ],
  40. ),
  41. ),
  42. );
  43. }
  44. }

Basic List Demo