🦄

【Flutter】SnackBarを上に表示したい

2023/11/15に公開

結論

私ごときの技術力では分かりませんでした。[完]
別の何かしらがないかなぁと調べていたら、MaterialBannerというものを見つけました。
パッと見た感じ「これでええやん!」と思って、試しに使ってみようと思いました。

popしたら逝った

SnackBarみたいに自動で消すようにもしておきたいなぁと思って、無理だろうとは感じながら、こんな感じに記載しました。

onVisible: () {
  Future.delayed(const Duration(seconds: 3), () {
    ScaffoldMessenger.of(context).removeCurrentMaterialBanner();                   });
},

無事にpopしたら逝きました。
いつまで経っても消えることはありませんでした。

対応

エントリポイントの部分MaterialApp.routerkeyを挿せるので、グローバルに使用できるようにProviderを作成しました(Providerにしなくてもいい)。

(keepAlive: true)
GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey(
        ScaffoldMessengerKeyRef ref) =>
    GlobalKey<ScaffoldMessengerState>();

で、これを挿す。

MaterialApp.router({
  scaffoldMessengerKey: ref.watch(scaffoldMessengerKeyProvider),
  // ry
});

MaterialBannerを使う側はこんな感じ。

final key = ref.watch(scaffoldMessengerKeyProvider);

key.currentState?.showMaterialBanner(
  MaterialBanner(
    margin: const EdgeInsets.all(10),
    elevation: 1,
    leading: const Icon(Icons.check),
    content: const Text('Successed'),
    actions: [
      TextButton(
        child: Text('close'),
        onPressed: () => key.currentState?.removeCurrentMaterialBanner(),
      ),
    ],
    onVisible: () {
      Future.delayed(
        const Duration(seconds: 3),
        () => key.currentState?.removeCurrentMaterialBanner(),
      );
    },
  ),
);

これはpopさせてないけど、見た目はこんな感じになる。
上に出てきてくれるSnackBarっぽいものは実現できる。

余談

elevationというプロパティがあるんですが、デフォルトでは0になっています。
ドキュメント読んで分かったんですが、これがデフォルトのままだと、バナーの大きさだけ、下にBodyが押し出されます(消えたら戻ります)。
ここの動きは好みだと思うので、押し出されるのが嫌な場合はプロパティをいじってみてください。

Discussion