本指南描述了如何在 Flutter 应用中将浮动应用栏或导航栏放置在列表上方。

概述

#

为了方便用户查看项目列表,你可能希望在用户向下滚动列表时最小化应用栏(导航栏)。

将应用栏移到 CustomScrollView 中,可以创建在滚动 CustomScrollView 中包含的项目列表时可以最小化或滚动到屏幕外的应用栏。

本指南演示了如何使用 CustomScrollView 来显示一个项目列表,并在其顶部带有一个应用栏,该应用栏在用户向下滚动列表时会最小化,具体步骤如下:

  1. 创建一个 CustomScrollView
  2. CustomScrollView 添加一个浮动应用栏。
  3. CustomScrollView 添加一个项目列表。

1. 创建一个 CustomScrollView

#

要创建浮动应用栏,请将应用栏放在 CustomScrollView 中,该 CustomScrollView 还包含项目列表。这可以同步应用栏和项目列表的滚动位置。你可以将 CustomScrollView 小部件视为一个 ListView,它允许你混合搭配不同类型的可滚动列表和小部件。

提供给 CustomScrollView 的可滚动列表和小部件被称为 *Slivers*。Slivers 有多种类型,例如 SliverListSliverGridSliverAppBar。实际上,ListViewGridView 小部件使用 SliverListSliverGrid 小部件来实现滚动。

对于此示例,创建一个包含 SliverListCustomScrollView。此外,如果代码中存在应用栏属性,请将其删除。

dart
MaterialApp(
  title: 'Floating App Bar',
  home: Scaffold(
    // No app bar property provided yet.
    body: CustomScrollView(
      // Add the app bar and list of items as slivers in the next steps.
      slivers: <widget>[],
    ),
  ),
);

dart
CupertinoApp(
  title: 'Floating Navigation Bar',
  home: CupertinoPageScaffold(
    // No navigation bar property provided yet.
    child: CustomScrollView(
      // Add the navigation bar and list of items as slivers in the next steps.
      slivers: <widget>[],
    ),
  ),
);

2. 添加一个浮动应用栏

#

接下来,向 CustomScrollView 添加一个应用栏。

Flutter 提供了 SliverAppBar 小部件,它与普通的 AppBar 小部件非常相似,使用 SliverAppBar 来显示标题、标签、图像等等。

但是,SliverAppBar 还允许你创建“浮动”应用栏,当不在页面顶部时,它会缩小并浮动。

要创建此效果

  1. 从一个只显示标题的应用栏开始。
  2. pinned 属性设置为 true
  3. 添加一个 flexibleSpace 小部件,它填充可用的 expandedHeight
dart
slivers: [
  // Add the app bar to the CustomScrollView.
  SliverAppBar(
    // Provide a standard title.
    title: Text('Floating App Bar'),
    // Pin the app bar when scrolling.
    pinned: true,
    // Display a placeholder widget to visualize the shrinking size.
    flexibleSpace: Placeholder(),
    // Make the initial height of the SliverAppBar larger than normal.
    expandedHeight: 200,
  ),
],

Flutter 提供了 CupertinoSliverNavigationBar 小部件,它允许你拥有一个“浮动”导航栏,当你向下滚动时它会缩小,当你不在页面顶部时它会浮动。

要创建此效果

  1. CupertinoSliverNavigationBar 添加到 CustomScrollView
  2. 从一个只显示标题的应用栏开始。
dart
slivers: [
  // Add the navigation bar to the CustomScrollView.
  CupertinoSliverNavigationBar(
    // Provide a standard title.
    largeTitle: Text('Floating App Bar'),
  ),
],

3. 添加一个项目列表

#

现在应用栏已就位,向 CustomScrollView 添加一个项目列表。你有两个选项:SliverListSliverGrid。如果你需要一个接一个地显示项目列表,请使用 SliverList 小部件。如果你需要显示网格列表,请使用 SliverGrid 小部件。

dart
// Next, create a SliverList
SliverList.builder(
  // The builder function returns a ListTile with a title that
  // displays the index of the current item.
  itemBuilder: (context, index) =>
      ListTile(title: Text('Item #$index')),
  // Builds 50 ListTiles
  itemCount: 50,
)
dart
// Next, create a SliverList
SliverList.builder(
  // The builder function returns a CupertinoListTile with a title
  // that displays the index of the current item.
  itemBuilder: (context, index) =>
      CupertinoListTile(title: Text('Item #$index')),
  // Builds 50 CupertinoListTile
  itemCount: 50,
)

互动示例

#
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const title = 'Floating App Bar';

    return MaterialApp(
      title: title,
      home: Scaffold(
        // No app bar provided to Scaffold, only a body with a
        // CustomScrollView.
        body: CustomScrollView(
          slivers: [
            // Add the app bar to the CustomScrollView.
            const SliverAppBar(
              // Provide a standard title.
              title: Text(title),
              // Pin the app bar when scrolling
              pinned: true,
              // Display a placeholder widget to visualize the shrinking size.
              flexibleSpace: Placeholder(),
              // Make the initial height of the SliverAppBar larger than normal.
              expandedHeight: 200,
            ),
            // Next, create a SliverList
            SliverList.builder(
              // The builder function returns a ListTile with a title that
              // displays the index of the current item.
              itemBuilder: (context, index) =>
                  ListTile(title: Text('Item #$index')),
              // Builds 50 ListTiles
              itemCount: 50,
            ),
          ],
        ),
      ),
    );
  }
}
import 'package:flutter/cupertino.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const title = 'Floating Navigation Bar';

    return CupertinoApp(
      title: title,
      home: CupertinoPageScaffold(
        // No navigation bar provided to CupertinoPageScaffold,
        // only a body with a CustomScrollView.
        child: CustomScrollView(
          slivers: [
            // Add the navigation bar to the CustomScrollView.
            const CupertinoSliverNavigationBar(
              // Provide a standard title.
              largeTitle: Text(title),
            ),
            // Next, create a SliverList
            SliverList.builder(
              // The builder function returns a CupertinoListTile with a title
              // that displays the index of the current item.
              itemBuilder: (context, index) =>
                  CupertinoListTile(title: Text('Item #$index')),
              // Builds 50 CupertinoListTile
              itemCount: 50,
            ),
          ],
        ),
      ),
    );
  }
}