FlutterサンプルアプリGalleryの縮小するヘッダを試す

Flutterサンプルアプリに[Gallery](https://github.com/flutter/flutter/tree/master/examples/flutter_gallery)があるが、このアプリの縮小（拡大）するヘッダがカッコよかったので、どうやってるのか調べてみた。

どうやら[CustomScrollView](https://docs.flutter.io/flutter/widgets/CustomScrollView-class.html)に、SliberAppBarとSliberListを指定して実装するらしい。SliberAppBarのbackgroundにはAnimatedBuilderを使用したWidgetも指定しアニメーションさせている様子。

チュートリアルの[Building Layouts in Flutter](https://flutter.io/tutorials/layout/)にあるlakesのレイアウトに移植して試してみる。

まず、バックグランド関連ソースをコピペし、背景画像のasset名を変更する。

```dart:lib/main.dart
const double _kFlexibleSpaceMaxHeight = 256.0;

class _BackgroundLayer {
  _BackgroundLayer({int level, double parallax})
      : assetName = 'images/lake.jpg',
        parallaxTween = new Tween<double>(begin: 0.0, end: parallax);
  final String assetName;
  final Tween<double> parallaxTween;
}

final List<_BackgroundLayer> _kBackgroundLayers = <_BackgroundLayer>[
  new _BackgroundLayer(level: 0, parallax: _kFlexibleSpaceMaxHeight),
  new _BackgroundLayer(level: 1, parallax: _kFlexibleSpaceMaxHeight),
  new _BackgroundLayer(level: 2, parallax: _kFlexibleSpaceMaxHeight / 2.0),
  new _BackgroundLayer(level: 3, parallax: _kFlexibleSpaceMaxHeight / 4.0),
  new _BackgroundLayer(level: 4, parallax: _kFlexibleSpaceMaxHeight / 2.0),
  new _BackgroundLayer(level: 5, parallax: _kFlexibleSpaceMaxHeight)
];

class _AppBarBackground extends StatelessWidget {
  _AppBarBackground({Key key, this.animation}) : super(key: key);

  final Animation<double> animation;

  @override
  Widget build(BuildContext context) {
    return new AnimatedBuilder(
        animation: animation,
        builder: (BuildContext context, Widget child) {
          return new Stack(
              children: _kBackgroundLayers.map((_BackgroundLayer layer) {
            return new Positioned(
                top: -layer.parallaxTween.evaluate(animation),
                left: 0.0,
                right: 0.0,
                bottom: 0.0,
                child: new Image.asset(layer.assetName,
                    fit: BoxFit.cover, height: _kFlexibleSpaceMaxHeight));
          }).toList());
        });
  }
}
```

次に、Scaffoldに渡していたappBarを削除し、bodyをCustomScrollViewに差し替える。画像はバックグランドの背景で指定したので、SliverListに渡す配列から取り除いておく。

```dart:lib/main.dart
    return new MaterialApp(
        title: 'Flutter Demo',
        theme: new ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: new Scaffold(
            body: new CustomScrollView(slivers: <Widget>[
          new SliverAppBar(
            pinned: true,
            expandedHeight: _kFlexibleSpaceMaxHeight,
            flexibleSpace: new FlexibleSpaceBar(
              title: new Text('Top Lakes'),
              // TODO(abarth): Wire up to the parallax in a way that doesn't pop during hero transition.
              background:
                  new _AppBarBackground(animation: kAlwaysDismissedAnimation),
            ),
          ),
          new SliverList(
              delegate: new SliverChildListDelegate(<Widget>[
            titleSection,
            buttonSection,
            textSection,
          ])),
        ])));
```

あと、直接関係ないけど、ヘッダが縮小しきるにはコンテンツが足りないので、テキストの文字列を適当に追加した。

で、できあがり。ソースは[ここ](https://github.com/tatsu/lakes)。

![Lakes](https://qiita-image-store.s3.amazonaws.com/0/49088/05ae51c0-0b7d-4633-8507-5270af3b1b94.gif)