Flutterでスナックバーを表示しようとすると発生するTypically, the ScaffoldMessenger widget is introduced by the MaterialApp at the top of your application widget tree.
をなんとかしたい!
概要
今回の記事では、Flutterでスナックバーを表示使用すると発生するTypically, the ScaffoldMessenger widget is introduced by the MaterialApp at the top of your application widget tree.
をなんとかする手順を掲載する。
こちらは専用のパッケージは不要。
仕様書
環境
- Android Studio Jellyfish | 2023.3.1 Patch 2
- Flutter 3.19.6
手順書
スナックバー表示する際の
ScaffoldMessenger.of(context).showSnackBar(snackBar)`
で使われるBuildContext
がMaterialApp
の中のScaffold
で作られてものである必要がある。
エラーが発生する例
import 'package:flutter/material.dart';
void main() {
runApp(SnackBarSample1());
}
class SnackBarSample1 extends StatelessWidget {
const SnackBarSample1({super.key});
@override
Widget build(BuildContext context) {
final snackBar = SnackBar(
action: SnackBarAction(
label: "Close",
onPressed: () => {ScaffoldMessenger.of(context).hideCurrentSnackBar()},
),
backgroundColor: Colors.lightBlue,
content: const Text("Nyahhhhn!"),
duration: const Duration(seconds: 5),
behavior: SnackBarBehavior.floating,
);
return
MaterialApp(
home: Scaffold(
body: SafeArea(
child: Center(
child: SizedBox(
width: double.infinity,
child: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.blue,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
),
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
),
onPressed: () => {
ScaffoldMessenger.of(context).showSnackBar(snackBar)
},
child: const Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
child: Text("Show Snack Bar",
style: TextStyle(fontSize: 16.0, color: Colors.white)),
),
),
),
),
),
),
),
);
}
}
この例だとMaterialApp
の外のBuildContext
が使われてるため、スナックバーを表示しようとした時にエラーは発生する。
エラーが発生しない例 (1)
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: const SnackBarSample1()
)
)
);
}
class SnackBarSample1 extends StatelessWidget {
const SnackBarSample1({super.key});
@override
Widget build(BuildContext context) {
final snackBar = SnackBar(
action: SnackBarAction(
label: "Close",
onPressed: () => {ScaffoldMessenger.of(context).hideCurrentSnackBar()},
),
backgroundColor: Colors.lightBlue,
content: const Text("Nyahhhhn!"),
duration: const Duration(seconds: 5),
behavior: SnackBarBehavior.floating,
);
return SafeArea(
child: Center(
child: SizedBox(
width: double.infinity,
child: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.blue,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
),
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
),
onPressed: () => {
ScaffoldMessenger.of(context).showSnackBar(snackBar)
},
child: const Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
child: Text("Show Snack Bar",
style: TextStyle(fontSize: 16.0, color: Colors.white)),
),
),
),
),
);
}
}
こんな感じでMaterialApp
の中のScaffold
で作られてるBuildContext
を使うとエラーが発生しない。
エラーが発生しない例 (2)
どうしても、クラスを分けたくない場合はMaterialApp
にGlobalKey
を設定してそれを使う。
import 'package:flutter/material.dart';
void main() {
runApp(SnackBarSample1());
}
class SnackBarSample1 extends StatelessWidget {
const SnackBarSample1({super.key});
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
final snackBar = SnackBar(
action: SnackBarAction(
label: "Close",
onPressed: () => {ScaffoldMessenger.of(navigatorKey.currentContext!).hideCurrentSnackBar()},
),
backgroundColor: Colors.lightBlue,
content: const Text("Nyahhhhn!"),
duration: const Duration(seconds: 5),
behavior: SnackBarBehavior.floating,
);
return
MaterialApp(
home: Scaffold(
body: SafeArea(
child: Center(
child: SizedBox(
width: double.infinity,
child: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.blue,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
),
padding: const EdgeInsets.fromLTRB(0, 0, 0, 0),
),
onPressed: () => {
ScaffoldMessenger.of(navigatorKey.currentContext!).showSnackBar(snackBar);
},
child: const Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
child: Text("Show Snack Bar",
style: TextStyle(fontSize: 16.0, color: Colors.white)),
),
),
),
),
),
),
),
navigatorKey: navigatorKey,
);
}
}
スナックバーを呼び出すコードも下記のように変わる。
ScaffoldMessenger.of(navigatorKey.currentContext!).showSnackBar(snackBar)
まとめ(感想文)
なかなかめんどい。