FlutterでSnackBarを表示する

# はじめに
SnakBarについて調べたので、備忘録として記事に残しておきます。

# 基本
以下のように`showSnackBar`メソッドの引数に`SnackBar`を指定し、読み出すと表示される。
```dart
const snackBar = SnackBar(
  content: Text("Normal SnackBar!!"),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/4856c60d-cdb3-26f8-2994-cec05c671ea6.png)

# 表示時間
Durationに指定した期間、画面に表示する。
指定しなかった場合は、デフォルトで４秒表示したら消える。

```dart
const snackBar = SnackBar(
  content: Text("Normal SnackBar!!"),
  duration: Duration(seconds: 1),
);
```

# 手動で消す
手動で消したい場合は以下のメソッドを呼べば消える。
```dart
ScaffoldMessenger.of(context).hideCurrentSnackBar();
```

SnackBarの表示は一個ずつになので、前のSnackBarが表示されている間、新しいSnackBarは表示されない。
なので、SnackBarが表示中に新しいのを表示したい場合、上のメソッドを呼ぶといい。

# イベントを追加
`action`に`SnackBarAction`を指定すると、イベントを追加できる。

```dart
final snackBar = SnackBar(
  content: const Text("Normal SnackBar!!"),
  action: SnackBarAction(
    label: "close",
    onPressed: () => ScaffoldMessenger.of(context).hideCurrentSnackBar(),
  ),
  duration: const Duration(seconds: 10),
);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/417ce085-793a-8c1e-5d3a-baa1e469d63b.png)

# 色の変更
`backgroundColor`で背景色を変更可能
```dart
const snackBar = SnackBar(
  backgroundColor:　Colors.red,
  content: Text("Normal SnackBar!!"),
  duration: Duration(seconds: 1),
);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/90fa07b9-c489-d350-ccc2-4796f11ca6e4.png)

# Padding
`padding`で`content`へのPaddingを調整可能。
画像のように、高さが変わるので注意。

```dart
const snackBar = SnackBar(
  content: Text("Normal SnackBar!!"),
  duration: Duration(seconds: 10),
  padding: EdgeInsets.only(left: 100),
);
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/cbf9dd3c-6b61-64c8-81c8-bcb1ba5b3cfa.png)


# 形状の変更
`shape`にプロパティを設定すると形状を変えられる。
```dart
    final snackBar = SnackBar(
      content: const Text("Normal SnackBar!!"),
      duration: const Duration(seconds: 10),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
    );
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/cdbf2186-0382-d058-a603-6663bc8e52d8.png)

設定できるのは`ShapeBorder`を継承したクラスのみ。

https://api.flutter.dev/flutter/painting/ShapeBorder-class.html

継承しているのは下記のクラス。
* [CircleBorder](https://api.flutter.dev/flutter/painting/CircleBorder-class.html)
* [RoundedRectangleBorder](https://api.flutter.dev/flutter/painting/RoundedRectangleBorder-class.html)
* [ContinuousRectangleBorder](https://api.flutter.dev/flutter/painting/ContinuousRectangleBorder-class.html)
* [BeveledRectangleBorder](https://api.flutter.dev/flutter/painting/BeveledRectangleBorder-class.html)

下記のクラスも可能（下記のクラスをさらに継承しているクラスもあり、そのクラスも可能）
* [BoxBorder](https://api.flutter.dev/flutter/painting/BoxBorder-class.html)
* [InputBorder](https://api.flutter.dev/flutter/material/InputBorder-class.html)
* [OutlinedBorder](https://api.flutter.dev/flutter/painting/OutlinedBorder-class.html)

# 横幅を変える
横幅を変えるには`margin`か`width`を指定する。
注意なのは、片方しか設定できないのと、設定するには`behavior`に`SnackBarBehavior.floating`を設定する必要があります。

```dart
final snackBar = SnackBar(
      content: const Text("Normal SnackBar!!"),
      duration: const Duration(seconds: 10),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
      margin: const EdgeInsets.only(left: 23, right: 23, bottom: 23),
      behavior: SnackBarBehavior.floating,
    );
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/1868a67d-84a3-c007-63e8-9319f0a9ce65.png)



:::note warn
`SnackBarBehavior.floating`にするとFloatingActionButtonがあった場合、上に表示されてしまうようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/9bab41f8-8352-c89a-488e-e5852e4549f5.png)

以下の記事を見ると、Scaffoldをネストすれば解決できそうですが本記事の主旨とズレるため検証はしていません。

https://stackoverflow.com/questions/58830257/flutter-how-to-make-snackbar-to-not-push-floatingactionbutton-upward
:::


# さらにカスタマイズ
`SnackBar`の`content`にはテキストだけじゃなく、Widgetが指定できるので、Rowを使えば、IconButtonも配置できます。

```
final snackBar = SnackBar(
      backgroundColor: Colors.grey,
      content: Row(children: [
        const Text(
          "Show SnackBar!!",
          style: TextStyle(
            fontSize: 14,
            color: Colors.white,
          ),
        ),
        Expanded(
          child: Container(
            height: 0,
          ),
        ),
        Padding(
          padding: EdgeInsets.zero,
          child: SizedBox(
            height: 24,
            width: 24,
            child: IconButton(
              padding: EdgeInsets.zero,
              icon: const Icon(Icons.account_balance),
              onPressed: () {
                ScaffoldMessenger.of(context).hideCurrentSnackBar();
              },
            ),
          ),
        ),
      ]),
      duration: const Duration(seconds: 10),
      shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
      margin: const EdgeInsets.only(left: 23, right: 23, bottom: 23),
      behavior: SnackBarBehavior.floating,
    );
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2475427/ae278cc8-c2cd-85a4-c3f4-9e4ab60741dd.png)

# 参考文献

https://ihilalahmadd.medium.com/customize-flutter-snackbar-example-383badb5b6b6