🐈

【Flutter Widget of the Week #11】SliverAppBarを使ってみた

2022/10/09に公開

はじめに

Flutter Widget of the Week #11 SliverAppBar についてまとめましたので、紹介します。
https://youtu.be/R9C5KMJKluE

SliverAppBar とは

SliverAppBar はスクロールさせた時にヘッダーのサイズを変化させたり、消したりできる Widget です。
Scaffold 内で AppBar Widget を使い、ヘッダーを作ることはよくあると思います。
しかし、 AppBar Widget はシンプルで便利な分、カスタム性が低いです。
もう少し凝ったヘッダーを作りたい! そんなときに SliverAppBar が効果的です。
それでは、実際に使ってみましょう。

SliverAppBar サンプル

まずは API Document にあるサンプルを動かしてみましょう。

main.dart
class _SliverAppBarExampleState extends State<SliverAppBarExample> {
  bool _pinned = true;
  bool _snap = false;
  bool _floating = false;

// [SliverAppBar]s are typically used in [CustomScrollView.slivers], which in
// turn can be placed in a [Scaffold.body].
  
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            pinned: _pinned,
            snap: _snap,
            floating: _floating,
            expandedHeight: 160.0,
            flexibleSpace: const FlexibleSpaceBar(
              title: Text('SliverAppBar'),
              background: FlutterLogo(),
            ),
          ),
          const SliverToBoxAdapter(
            child: SizedBox(
              height: 20,
              child: Center(
                child: Text('Scroll to see the SliverAppBar in effect.'),
              ),
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return Container(
                  color: index.isOdd ? Colors.white : Colors.black12,
                  height: 100.0,
                  child: Center(
                    child: Text('$index', textScaleFactor: 5),
                  ),
                );
              },
              childCount: 20,
            ),
          ),
        ],
      ),
      bottomNavigationBar: BottomAppBar(
        child: Padding(
          padding: const EdgeInsets.all(8),
          child: OverflowBar(
            overflowAlignment: OverflowBarAlignment.center,
            children: <Widget>[
              Row(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  const Text('pinned'),
                  Switch(
                    onChanged: (bool val) {
                      setState(() {
                        _pinned = val;
                      });
                    },
                    value: _pinned,
                  ),
                ],
              ),
              Row(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  const Text('snap'),
                  Switch(
                    onChanged: (bool val) {
                      setState(() {
                        _snap = val;
                        // Snapping only applies when the app bar is floating.
                        _floating = _floating || _snap;
                      });
                    },
                    value: _snap,
                  ),
                ],
              ),
              Row(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  const Text('floating'),
                  Switch(
                    onChanged: (bool val) {
                      setState(() {
                        _floating = val;
                        _snap = _snap && _floating;
                      });
                    },
                    value: _floating,
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

使い方として、
まず、SliverAppBar は CustomScrollView と一緒に使います。
なぜなら SliverAppBar は通常の AppBar のように Scaffold の appBar プロパティでそのまま使うことができないからです。
そのため、Scaffold の body プロパティに CustomScrollView を作り、
CustomScrollView の slivers プロパティでリストの一つとして SliverAppBar を設定します。

expandedHeight でAppBar の高さを指定し、
flexibleSpace で AppBar に表示する画像や文字を設定します。
他にもプロパティはありますが、expandedHeight と flexibleSpace を設定するだけでも形になります。
以上が基本的な使い方です。

SliverAppBar のプロパティについて

SliverAppBar にはたくさんのプロパティがあります。
いくつか紹介します。

(new) SliverAppBar SliverAppBar({
  Key? key,
  Widget? leading,
  bool automaticallyImplyLeading = true,
  Widget? title,
  List<Widget>? actions,
  Widget? flexibleSpace,
  PreferredSizeWidget? bottom,
  double? elevation,
  double? scrolledUnderElevation,
  Color? shadowColor,
  Color? surfaceTintColor,
  bool forceElevated = false,
  Color? backgroundColor,
  Color? foregroundColor,
  Brightness? brightness,
  IconThemeData? iconTheme,
  IconThemeData? actionsIconTheme,
  TextTheme? textTheme,
  bool primary = true,
  bool? centerTitle,
  bool excludeHeaderSemantics = false,
  double? titleSpacing,
  double? collapsedHeight,
  double? expandedHeight,
  bool floating = false,
  bool pinned = false,
  bool snap = false,
  bool stretch = false,
  double stretchTriggerOffset = 100.0,
  Future<void> Function()? onStretchTrigger,
  ShapeBorder? shape,
  double toolbarHeight = kToolbarHeight,
  double? leadingWidth,
  bool? backwardsCompatibility,
  TextStyle? toolbarTextStyle,
  TextStyle? titleTextStyle,
  SystemUiOverlayStyle? systemOverlayStyle,
})

①expandedHeight

AppBar の高さを設定する
型は double 型

②flexibleSpace

ツールバーとタブバーの後ろに表示する Widget を設定する
型は Widget 型

③floating

上方向にスクロールをしたときに AppBar を表示するかどうかを指定する
デフォルトは false
型は bool 型

④pinned

下方向にスクロールをしたときも常に AppBar を表示するよう指定する
デフォルトは false
型は bool 型

⑤snap

上方向にスクロールすると AppBar を完全に展開するかどうかを指定する
floating が true の時にのみ snap をtrue に指定できる
デフォルトは false
型は bool 型

⑥stretch

AppBar をオーバースクロール領域まで伸ばすかどうかを設定する
デフォルトは false
型は bool 型

⑦leading

AppBar のタイトルの前に表示する Widget を設定する
(AppBar の左側に入れる Widget を設定できる)
型は Widget 型

⑥actions

AppBar のタイトルの後ろに一列に表示する Widget のリストを設定する
(AppBar の右側に入れる Widget を設定できる)
型は List<Widget> 型

追加: SliverAppBar サンプル2

通常の AppBar と併用することもできます。

main.dart
class SliverAppBarExample extends StatefulWidget {
  const SliverAppBarExample({super.key});

  
  State<SliverAppBarExample> createState() => _SliverAppBarExampleState();
}

class _SliverAppBarExampleState extends State<SliverAppBarExample> {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('AppBar'),
      ),
      body: CustomScrollView(
        slivers: <Widget>[
          const SliverAppBar(
	    backgroundColor: Colors.red,
            floating: true,
            pinned: true,
            snap: true,
            expandedHeight: 150.0,
            flexibleSpace: FlexibleSpaceBar(
              title: Text('SliverAppBar'),
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => ListTile(title: Text('list item $index')),
              childCount: 20,
            ),
          ),
          SliverGrid(
            gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
              maxCrossAxisExtent: 200.0,
              mainAxisSpacing: 10.0,
              crossAxisSpacing: 14.0,
              childAspectRatio: 7.0,
            ),
            delegate: SliverChildBuilderDelegate(
              (BuildContext context, int index) {
                return Container(
                  alignment: Alignment.center,
                  color: Colors.teal[100 * (index % 8)],
                  child: Text('grid item $index'),
                );
              },
              childCount: 20,
            ),
          ),
        ],
      ),
    );
  }
}

サンプル2で用いた SliverList と SliverGrid は次回のテーマになりますので、気になる人は次回をお楽しみに!

最後に

今回は SliverAppBar を紹介しました。
SliverAppBar はたくさんプロパティがあり、カスタマイズしがいのある Widget ですね。
メインとなる部分だけでなく、AppBarという細かな部分もこだわってみるとより面白いアプリが作れると思います。ぜひ試してみてください。
次は #12 SliverList and SliverGrid です。またお会いしましょう。

参考記事

https://api.flutter.dev/flutter/material/SliverAppBar-class.html
https://flutter.ctrnost.com/basic/navigation/sliverappbar/

Discussion