画面をスクロールしたらヘッダーが消えたりするやつを実装する(Sliver)  

# 概要

画面をスクロールしたらヘッダーがが出たり消えたりするやつを実装します。

![sliver-flutter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/201135/3e66e0f2-e35b-2651-2677-ad09fcc2a115.gif)

# Sliver

上のようなスクロールに伴ってエフェクトが発生するUIはFlutterにおいてSliver(細長い小片)と呼ばれます。

また、Airbnbの例のようにスクロールに伴って出たり消えたりするAppBarは`SliverAppBar`クラスで実装されます。

https://api.flutter.dev/flutter/material/SliverAppBar-class.html

[基礎から学ぶFlutter](https://www.amazon.co.jp/dp/B082XQ81FH)にも記述があります。

# 出来上がるコード/UI

最終的には以下のようなbuildメソッドが出来上がるはず。

```dart
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            flexibleSpace: FlexibleSpaceBar(
              background: Image(
                fit: BoxFit.fill,
                image: AssetImage('path/to/asset.jpg'),
              ),
            ),
            expandedHeight: 300,
            backgroundColor: Colors.transparent,
          ),
          SliverList(
            delegate: SliverChildListDelegate(
              <Widget>[...],
            ),
          ),
        ],
      ),
```



# 作っていく

## なにはともあれScaffold

とりあえずScaffoldを置きましょう。

```dart
build(BuildContext context) {
  return Scaffold()
}
```

## 基礎になるCustomScrollViewを置く

[`CustomScrollView`](https://api.flutter.dev/flutter/widgets/CustomScrollView-class.html)というクラスがあります。

```dart
build(BuildContext context) {
  return Scaffold(
    body: CustomScrollView(
      sliver: <Widget>[]
    )
  )
}

```

## ヘッダとしてSliverAppBarを置く

今回のメインです。
[SliverAppBar](https://api.flutter.dev/flutter/material/SliverAppBar-class.html)はスクロールに応じて隠れたり出現したりするAppBarです。

通常のAppBarと同じように、leading, title, actionsといった引数を持ちます。

これを置くのですが、`CustomScrollView`はappBarをコンストラクタの引数に持たないため、sliversの一番上にSliverAppBarを置きます。ちょっと気持ち悪い。

```dart
build(BuildContext context) {
  return Scaffold(
    body: CustomScrollView(
      sliver: <Widget>[
        SliverAppBar(),
      ],
    ),
  ),
}
```

## SliverAppBarの引数を詰める

`flexibleSpace`という引数があり、ヘッダのコンテンツとして入れたいウィジェットはこれの中に入れてください。まとめるとだいたい以下のようになると思います。

```dart
build(BuildContext context) {
  return Scaffold(
    body: CustomScrollView(
      sliver: <Widget>[
        SliverAppBar(
          flexibleSpace: FlexibleSpaceBar(
            background: Image(
              fit: BoxFit.fill,
              image: AssetImage('assets/gift/item74.jpg'),
            ),
          ),
          expandedHeight: 300,
          backgroundColor: Colors.transparent,),
        )
      ],
    ),
  ),
}
```

画像をヘッダに表示する場合、`FlexibleSpaceBar`の`background`に`Image`を指定し、その上で`fit: BoxFit.fill`を指定してください。
これを指定しないと画像が端まで伸びてくれません。

> Most commonly used in in the SliverAppBar.flexibleSpace field, 


ぶっちゃけ`FlexibleSpaceBar`はSliver以外ほぼ使わないみたいなのでお作法だと思って覚えたほうが早いです。頑張りましょう。

https://api.flutter.dev/flutter/material/FlexibleSpaceBar-class.html

## コンテンツとして表示する部分をsliversの下に詰める

sliversには[`SliverList`](https://api.flutter.dev/flutter/widgets/SliverList-class.html)を入れます。

`SliverList.delegate`に詰めるウィジェットは大きく分けて2種類あります。

### 1. コンテンツを並べる場合

`SliverChildListDelegate`コンストラクタにウィジェットの配列を与えてください。以下のような感じです。

```dart

SliverList(
  delegate: SliverChildListDelegate(
    <Widget>[
      Container(
        padding: EdgeInsets.all(24),
        child: Column( ...

```

### 2. グリッドやリストを並べる場合

[SliverChildBuilderDelegate](https://api.flutter.dev/flutter/widgets/SliverChildBuilderDelegate-class.html)でbuilderを定義できます。以下のような雰囲気です。

```dart
SliverList(
  delegate: SliverChildBuilderDelegate(
    (BuildContext context, int index) {
       return Text('...');
     },
     childCount: 2,
     semanticIndexOffset: 2,
   ),
 ),
```

# まとめ

Sliverは用語がよく分からなかったりdelegateがよく分かんなかったりしますが、一回実装すれば割と分かりやすいので頑張りましょう

### 余談

この記事書くまで`Sliver`のことを`Sliver`(銀)だと思ってました