概要
今回の要件は、ユーザー情報登録画面にて登録ボタンをクリックした際にToastで「完了しました」と表示すると同時に登録画面から前の画面に戻ることです。
- Toastの表示にはFlutterToastを使いました
- SnackbarはScaffoldに紐づくため前画面に戻るタイミングで消えてしまう
詳細
Toastの表示にはFlutterToastを使いました
import 'package:fluttertoast/fluttertoast.dart';
// ユーザー設定画面
class UserSettingPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(title: Text(Strings.of(context).registerUserInformation)),
body: UserSettingWidget(
onRegistered: () {
Navigator.pop(context);
// Toast表示
Fluttertoast.showToast(msg: "完了しました");
},
),
);
}
}
SnackbarはScaffoldに紐づくため前画面に戻るタイミングで消えてしまう
上記のコードをToastではなくSnackbarにした場合。
/// ユーザー設定画面
class UserSettingPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(title: Text(Strings.of(context).registerUserInformation)),
// Scaffoldを含むcontextを受け取るためBuilderでラップ
body: Builder(
builder: (BuildContext context) {
return UserSettingWidget(
onRegistered: () {
Navigator.pop(context);
// Snackbar表示
Scaffold.of(context).showSnackBar(SnackBar(content: const Text("完了しました")));
},
);
},
),
);
}
}
動作的には問題ありませんが、SnackbarはScaffoldに紐づくためユーザー設定画面がNavigator.pop(context)
で破棄されたタイミングでSnackbarも一緒に破棄されてしまいます。
画面ごとなくなってしまうイメージです。
したがって、今回はSnackbarではなくToastを表示するようにしています。
ちなみに、Snackbar表示の際にBuilder
を使わなかった場合は下記のエラーが発生します。
I/flutter (10607): ══╡ EXCEPTION CAUGHT BY GESTURE ╞═══════════════════════════════════════════════════════════════════
I/flutter (10607): The following assertion was thrown while handling a gesture:
I/flutter (10607): Scaffold.of() called with a context that does not contain a Scaffold.
I/flutter (10607): No Scaffold ancestor could be found starting from the context that was passed to Scaffold.of(). This
I/flutter (10607): usually happens when the context provided is from the same StatefulWidget as that whose build
I/flutter (10607): function actually creates the Scaffold widget being sought.
I/flutter (10607): There are several ways to avoid this problem. The simplest is to use a Builder to get a context that
I/flutter (10607): is "under" the Scaffold. For an example of this, please see the documentation for Scaffold.of():
I/flutter (10607): https://docs.flutter.io/flutter/material/Scaffold/of.html
I/flutter (10607): A more efficient solution is to split your build function into several widgets. This introduces a
I/flutter (10607): new context from which you can obtain the Scaffold. In this solution, you would have an outer widget
I/flutter (10607): that creates the Scaffold populated by instances of your new inner widgets, and then in these inner
I/flutter (10607): widgets you would use Scaffold.of().
I/flutter (10607): A less elegant but more expedient solution is assign a GlobalKey to the Scaffold, then use the
I/flutter (10607): key.currentState property to obtain the ScaffoldState rather than using the Scaffold.of() function.
I/flutter (10607): The context used was:
I/flutter (10607): UserSettingPage(dependencies: [_LocalizationsScope-[GlobalKey#fc80a]])
I/flutter (10607):
I/flutter (10607): When the exception was thrown, this was the stack:
I/flutter (10607): #0 Scaffold.of (package:flutter/src/material/scaffold.dart:1019:5)
I/flutter (10607): #1 UserSettingPage.build.<anonymous closure> (package:hoge/ui/setting/user_setting.dart:15:20)
I/flutter (10607): #2 _UserSettingWidgetState._buildRegisterButton.<anonymous closure> (package:hoge/ui/widget/user_setting_widget.dart:318:17)
I/flutter (10607): #3 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:513:14)
I/flutter (10607): #4 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:568:30)
I/flutter (10607): #5 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:120:24)
I/flutter (10607): #6 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
I/flutter (10607): #7 TapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:204:7)
I/flutter (10607): #8 GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:156:27)
I/flutter (10607): #9 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:218:20)
I/flutter (10607): #10 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:192:22)
I/flutter (10607): #11 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:149:7)
I/flutter (10607): #12 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:101:7)
I/flutter (10607): #13 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:85:7)
I/flutter (10607): #17 _invoke1 (dart:ui/hooks.dart:223:10)
I/flutter (10607): #18 _dispatchPointerDataPacket (dart:ui/hooks.dart:144:5)
I/flutter (10607): (elided 3 frames from package dart:async)
I/flutter (10607):
I/flutter (10607): Handler: onTap
I/flutter (10607): Recognizer:
I/flutter (10607): TapGestureRecognizer#66fbf(debugOwner: GestureDetector, state: ready, won arena, finalPosition:
I/flutter (10607): Offset(234.6, 511.6), sent tap down)
I/flutter (10607): ════════════════════════════════════════════════════════════════════════════════════════════════════