💻
[Flutter] SnackBarを使おうとすると Scaffold.of() called with(略)と言われるときの対応
小ネタです。
Flutterで SnackBar を使おうとしたら
Scaffold.of() called with a context that does not contain a Scaffold.
みたいな感じで怒られたことありますよね。
ちなみにエラーの全文は以下。
══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════ The following assertion was thrown while handling a gesture: Scaffold.of() called with a context that does not contain a Scaffold. No Scaffold ancestor could be found starting from the context that was passed to Scaffold.of(). This usually happens when the context provided is from the same StatefulWidget as that whose build function actually creates the Scaffold widget being sought. There are several ways to avoid this problem. The simplest is to use a Builder to get a context that is "under" the Scaffold. For an example of this, please see the documentation for Scaffold.of(): https://api.flutter.dev/flutter/material/Scaffold/of.html A more efficient solution is to split your build function into several widgets. This introduces a new context from which you can obtain the Scaffold. In this solution, you would have an outer widget that creates the Scaffold populated by instances of your new inner widgets, and then in these inner widgets you would use Scaffold.of(). A less elegant but more expedient solution is assign a GlobalKey to the Scaffold, then use the key.currentState property to obtain the ScaffoldState rather than using the Scaffold.of() function. The context used was: Settings When the exception was thrown, this was the stack: #0 Scaffold.of package:flutter/…/material/scaffold.dart:1451 #1 _SettingsState.build.<anonymous closure> package:match/pages/settings.dart:86 #2 _InkResponseState._handleTap package:flutter/…/material/ink_well.dart:992 #3 _InkResponseState.build.<anonymous closure> package:flutter/…/material/ink_well.dart:1098 #4 GestureRecognizer.invokeCallback package:flutter/…/gestures/recognizer.dart:184 #5 TapGestureRecognizer.handleTapUp package:flutter/…/gestures/tap.dart:524 #6 BaseTapGestureRecognizer._checkUp package:flutter/…/gestures/tap.dart:284 #7 BaseTapGestureRecognizer.acceptGesture package:flutter/…/gestures/tap.dart:256 #8 GestureArenaManager.sweep package:flutter/…/gestures/arena.dart:158
このような場合の対策についてです。
結論としては、内部で SnackBar
を使いたいウィジェットを Builder
でラップしてあげて、新しい BuildContext
を使って SnackBar
を出力してあげればエラーになりません。
Before
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ほげ'),
),
body: Center(
child: RaisedButton(
child: Text('保存'),
onPressed: () {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('SnackBarは正常に動作しません'),
)),
},
),
),
);
}
After
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ほげ'),
),
body: Builder(
builder: (BuildContext context) {
return Center(
child: RaisedButton(
child: Text('保存'),
onPressed: () {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('SnackBarが正常に動作します'),
));
},
),
);
},
),
);
}
こんな感じ。
参考:flutter - Scaffold.of() called with a context that does not contain a Scaffold - Stack Overflow
他にも
-
SnackBar
の代わりに fluttertoast パッケージを使う -
get パッケージを使って
BuildContext
不要でSnackBar
を出力できるようにする
といった方法も検討してみてもいいかもしれません。
get
ライブラリを使う場合は、ライブラリをインストールするだけではなく、公式ドキュメント のStep 1
Step 2
Step 3
の手順で準備をしないと動作しないので要注意です。
Discussion