【Flutter】Snackbar(スナックバー)をちょっとお洒落にする

対象者

  • Flutterでスナックバーを表示したい人
  • せっかくなので、パッケージは使わずに、ちょっとおしゃれなスナックバーにしたい人

アプリの画面

はじめに

Flutterの標準のスナックバー動作確認をしたので、方法を記載しておきます。

Figma Material X kit – Snackbar components UI designに、シンプルかつおしゃれなスナックバーがあったので、Flutter標準で実装できないかなぁ、と実験しました。残念ながら色つきの影はできないようです。

実施するソース

そのまま カスタマイズ
スナックバーのデフォルト スナックバーのカスタマイズ

とりあえず、表示する場合

final simpleSnackBar = SnackBar(content: Text('snapbar'));
ScaffoldMessenger.of(context).showSnackBar(simpleSnackBar);

スナックバーをカスタマイズして表示する場合

 final snackBar = SnackBar(
  padding: const EdgeInsetsDirectional.symmetric(horizontal: 16),
  margin: const EdgeInsetsDirectional.all(16),
  content: Padding(
    padding: EdgeInsets.all(8.0),
    child: Row(
      children: const [
        Icon(
          Icons.check,
          color: Colors.green,
        ),
        Text(
          'Conguraturation!',
          style: TextStyle(color: Colors.green),
        ),
        Padding(
          padding: EdgeInsets.symmetric(horizontal: 8),
          child: Text(
            'Added!',
            style: TextStyle(color: Colors.black),
          ),
        ),
      ],
    ),
  ),
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(10),
  ),
  behavior: SnackBarBehavior.floating,
  showCloseIcon: true,
  onVisible: () {
    print('snackbar was shown');
  },
  action: SnackBarAction(
    label: 'Public',
    textColor: Colors.green,
    onPressed: () {
      print('snackbar actin was pressed');
    },
  ),
  elevation: 4.0,
  backgroundColor: Colors.white,
  closeIconColor: Colors.green,
  clipBehavior: Clip.hardEdge,
  dismissDirection: DismissDirection.horizontal,
);

カスタマイズ項目:

  • behavior
    デフォルトでは下に表示される。floatingを設定すると、浮いた感じに表示される
  • margin
    floating に設定しておかないと、エラーになる。floating状態で周りにどれくらい幅を持たせるかを設定
  • padding
    contentに指定したWidgetの周りの幅
  • content
    スナックバーに表示するWidget
  • shape
    スナックバーの外枠の形。
    RoundedRectangleBorder(borderRadius: BorderRadius.circular(10),) とすると角円になる。
  • showCloseIcon, closeIconColor
    showCloseIconをtrueにすると閉じるアイコンを表示させることができる。デフォルトでは表示されない。
    closeIconColorで閉じるアイコンの色を設定する
  • onVisible
    スナックバーが表示されたときに実施するイベント
  • dismissDirection
    スナックバーを消すときのユーザの動作。
  • action
    スナックバーの閉じるアイコンの左側、閉じるアイコンがなければ一番右側に、押すとイベントを実施するテキストを設定できる
  • elevation
    影の幅を設定できる。色を設定する方法は分からなかった(知っている方、教えて!)

まとめ

Flutter標準のスナックバーでどこまでおしゃれにできるか挑戦しました。あと、影の色さえ指定できれば大体できるかな、と思いました。
awesome_snackbar_content を使えば良いかと思いますが、もうちょいシンプルなやつを作ってみたかった。

参考

全ソース

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  void _incrementCounter() {
    final snackBar = SnackBar(
      behavior: SnackBarBehavior.floating,
      padding: const EdgeInsetsDirectional.symmetric(horizontal: 16),
      margin: const EdgeInsetsDirectional.all(16),
      content: Row(
        children: const [
          Icon(
            Icons.check,
            color: Colors.green,
          ),
          Text(
            'Conguraturation!',
            style: TextStyle(color: Colors.green),
          ),
          Padding(
            padding: EdgeInsets.symmetric(horizontal: 8),
            child: Text(
              'Added!',
              style: TextStyle(color: Colors.black),
            ),
          ),
        ],
      ),
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(10),
      ),
      showCloseIcon: true,
      onVisible: () {
        print('snackbar was shown');
      },
      action: SnackBarAction(
        label: 'Public',
        textColor: Colors.green,
        onPressed: () {
          print('snackbar actin was pressed');
        },
      ),
      elevation: 4.0,
      backgroundColor: Colors.white,
      closeIconColor: Colors.green,
      clipBehavior: Clip.hardEdge,
      dismissDirection: DismissDirection.horizontal,
    );
    final simpleSnackBar = SnackBar(content: Text('snapbar'));
    ScaffoldMessenger.of(context).showSnackBar(snackBar);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Container(),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: _incrementCounter,
      ),
    );
  }
}

蛇足

スナックバーとスナップバーをよく間違えた。