頂端工具列 AppBar


ScaffoldappBar 特性,可以用來設置頂端工具列,在之前的文件中,只都有隨便塞個 AppBar 實例,設置一下文字標題罷了,那麼 appBar 是什麼呢?如果查詢 API 文件,會發現 appBar 的型態不過就是 PreferredSizeWidget

PreferredSizeWidget 只有一個 preferredSize 取值方法(Getter)要實現,傳回的 Size 實例,是這個 Widget 的偏好尺寸,也就是可以的話,請使用這個尺寸的資訊,作為佈局的參考依據。

例如,稍後會看到,AppBar 本身也可以設置一個 bottom 元件,如果你設置了 bottom 元件,當然會希望 AppBar 的高度,至少有 bottom 元件的大小吧!

因此,如果有設置 bottom 的話,AppBar 會參考 bottompreferredSize.height 資訊(bottom 接受的型態也是 PreferredSizeWidget),加上 kToolbarHeight(56 像素),作為它的 AppBar 的偏好高度;如果沒有 bottom,或 bottom.preferredSize 沒設,或沒有 bottom.preferredSize.height,那 AppBar 偏好高度就是 56,也就是使用 kToolbarHeight

如果 Scaffold 設置了 appBar,則會用 appBar.preferredSize.height 加上頂端墊充作為高度。

既然如此,就表示只要實作 PreferredSizeWidget,就可以把任何自訂的元件,指定給 appBar 了,例如,來隨便自訂一個簡單的頂端文字列:

import 'package:flutter/material.dart';

void main() => runApp(
  MaterialApp(
    home: Scaffold(
      appBar: TextTitle('openhome.cc'),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Center(
            child: Image.asset('images/caterpillar.png'),
          ),
          Text('我是一隻弱小的毛毛蟲,想像有天可以成為強壯的挖土機,擁有挖掘夢想的神奇手套!')
        ],
      ),
    ),
  )
);

class TextTitle extends StatelessWidget implements PreferredSizeWidget {
  final text;

  TextTitle(this.text);

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Text(
          text,
          style: TextStyle(
            fontSize: 28,
            color: Colors.white,
          )
        )
      ),
      color: Colors.blue,
    );
  }

  @override
  Size get preferredSize => Size.fromHeight(kToolbarHeight);
}

執行結果如下:

頂端工具列 AppBar

當然,這是在 Flutter 提供的 AppBarTabBar(它們都實作了 PreferredSizeWidget)無法滿足需求時,才需要做的事,這邊先來看 AppBar,理解它作用最重要的就是 API 官方文件中這張圖:

頂端工具列 AppBar

leadingtitleflexibleSpace 接受的都是 Widgetactions 的型態是 List<Widget>,也就是一組 Widgetbottom 如前所述,可以是實作了 PreferredSizeWidget 的元件。

只要符合各特性接受的型態,基本上想放什麼就都是個人自由了,例如,leading 常會放個具有 Icons.menu 的按鈕之類的元件,表示可以展開選單;title 就是之前常用的了,通常會放個文字,不過想放個圖基本上也沒問題;actions 大概是這個頁面的常用操作,可以是使用特定圖示外觀之類的按鈕;bottoms 我想到的是可用在展示圖片時,顯示目前是在第幾張圖片,像是分頁指示之類的東西,或者你要把 TabBar 塞進去,實作個頂端的分頁導覽也行;flexibleSpace 就彈性應用吧!

底下的範例,純綷就目前學過的東西,塞到 AppBar 裏做些畫面上的展示,其中 TabBar 的使用,之後會再談,先看看外觀就好:

import 'package:flutter/material.dart';

void main() => runApp(
  MaterialApp(
    home: DefaultTabController(
      length: 3,
      child: Scaffold(
        appBar: AppBar(
          leading: IconButton(
            icon: Icon(
              Icons.menu,
              color: Colors.white,
            ),
            onPressed: () => print('按下選單'),
          ),
          title: Text('Openhome.cc'),
          actions: [
            IconButton(
              icon: Icon(
                Icons.pets,
                color: Colors.white,
              ),
              onPressed: () => print('按下狗掌'),
            ),
            IconButton(
              icon: Icon(
                Icons.search,
                color: Colors.white,
              ),
              onPressed: () => print('按下搜尋'),
            )
          ],
          bottom: TabBar(
            tabs: [
              Tab(text: 'Java'),
              Tab(text: 'Python'),
              Tab(text: 'JavaScript'),
            ],
          ),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Center(
              child: Image.asset('images/caterpillar.png'),
            ),
            Text('我是一隻弱小的毛毛蟲,想像有天可以成為強壯的挖土機,擁有挖掘夢想的神奇手套!')
          ],
        ),
      ),
    )
  )
);

執行後的畫面如下:

頂端工具列 AppBar