本指南說明如何在 Flutter 應用程式中,將浮動 app bar 或導覽列放置於清單上方。

概覽

#

為了讓使用者更方便瀏覽項目清單,您可能會希望在使用者往下捲動清單時,最小化 app bar(導覽列)。

將 app bar 移入 CustomScrollView,可以讓您建立一個可最小化或隨著清單捲動而隱藏的 app bar,而這個清單的項目則包含在 CustomScrollView 之中。

本教學將示範如何使用 CustomScrollView,在清單上方顯示一個 app bar,並在使用者往下捲動清單時自動最小化,步驟如下:

  1. 建立 CustomScrollView
  2. CustomScrollView 中加入浮動 app bar。
  3. CustomScrollView 中加入項目清單。

1. 建立 CustomScrollView

#

若要建立浮動 app bar,請將 app bar 放入同時包含項目清單的 CustomScrollView 中。這樣可以同步 app bar 與項目清單的捲動位置。您可以將 CustomScrollView 元件(Widget)想像成一個允許您混合搭配不同類型可捲動清單與元件的 ListView

提供給 CustomScrollView 的可捲動清單與元件稱為 slivers。slivers 有多種類型,例如 SliverListSliverGridSliverAppBar。事實上,ListViewGridView 元件就是利用 SliverListSliverGrid 元件來實作捲動功能。

在本範例中,請建立一個包含 SliverListCustomScrollView。如果您的程式碼中有 app bar 屬性,請將其移除。

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. 新增浮動應用程式列(floating app bar)

#

接下來,將應用程式列(app bar)加入到CustomScrollView

Flutter 提供了 SliverAppBar 元件(Widget), 它與一般的 AppBar 元件類似, 同樣使用 SliverAppBar 來顯示標題、 分頁(tabs)、圖片(images)等內容。

然而,SliverAppBar 還提供了 建立「浮動」應用程式列(floating app bar)的能力, 當你不在頁面頂端時,該列會縮小並浮動顯示。

要實現這個效果:

  1. 先建立一個僅顯示標題的應用程式列(app bar)。
  2. pinned 屬性設為 true
  3. 加入一個 flexibleSpace 元件(Widget),讓它填滿可用的 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 元件(Widget),讓你可以擁有一個「浮動」的導覽列, 當你向下滾動時會縮小,當你不在頁面頂部時則會浮動顯示。

要實現這個效果:

  1. CupertinoSliverNavigationBar 加入到 CustomScrollView 中。
  2. 先建立一個只顯示標題的 app bar。
dart
slivers: [
  // Add the navigation bar to the CustomScrollView.
  CupertinoSliverNavigationBar(
    // Provide a standard title.
    largeTitle: Text('Floating App Bar'),
  ),
],

3. 新增項目清單

#

現在你已經建立好 app bar,接下來要在 CustomScrollView 中新增一個項目清單。你有兩種選擇:SliverListSliverGrid。如果你需要將多個項目依序顯示,請使用 SliverList 元件 (Widget);如果你需要顯示格狀清單,則請使用 SliverGrid 元件 (Widget)。

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,
            ),
          ],
        ),
      ),
    );
  }
}