[2019/05/13 追記] Issue#29596 は プルリク 30422 で修正されました。 [2019/04/01 追記] #29596 によると、iOSでスワイプで戻ると didPop, didPopNext が呼ばれないようです。
FlutterのWidgetには、画面の遷移に関するイベントを処理するためのハンドラ(メソッド)がありません。これは当然で、Widgetは部品であるため、画面の一部なのか全体なのか、使う側次第だからです。
さて、Flutterにおいて画面遷移に関する処理を行っているのはNavigatorというクラスです。このクラスに対してpushやpopという操作を行います。このNavigatorに対してはNavigatorObserverのリストを渡すことができます。これにより画面遷移に関するイベントを受け取ることができます。
NavigatorObserverを実装したクラスを自分で実装して処理してもよいのですが、それをStateで処理することが目的であれば、RouteObserverというものを使うと便利です。
以下のようにMaterialAppやWidgetsAppにオブザーバーを設定しておきます。
final RouteObserver<PageRoute> routeObserver = new RouteObserver<PageRoute>();
Widget build(BuildContext context) {
...
return new MaterialApp(
...
navigatorObservers: <NavigatorObserver>[routeObserver],
...
);
}
続いて、StateにRouteAwareをmixinして、routeObserverに対してsubscribe/unsubscribeします。
class YourPageWidgetState extends State<YourPageWidget> with RouteAware {
@override
void didChangeDependencies() {
super.didChangeDependencies();
routeObserver.subscribe(this, ModalRoute.of(context));
}
@override
void dispose() {
routeObserver.unsubscribe(this);
super.dispose();
}
// 上の画面がpopされて、この画面に戻ったときに呼ばれます
void didPopNext() {
debugPrint("didPopNext ${runtimeType}");
}
// この画面がpushされたときに呼ばれます
void didPush() {
debugPrint("didPush ${runtimeType}");
}
// この画面がpopされたときに呼ばれます
void didPop() {
debugPrint("didPop ${runtimeType}");
}
// この画面から新しい画面をpushしたときに呼ばれます
void didPushNext() {
debugPrint("didPushNext ${runtimeType}");
}
}
新しい画面が呼ばれるときに:
- 呼び出し元で didPushNext
- 呼び出し先で disPush
画面を戻るときに:
- 戻る元で disPop
- 戻る先で disPopNext
が呼ばれます。
どの画面でも共通の処理があるのであれば、基底クラスとしてRouteAwareStateのようなものを作り、各画面のStateはそれをextendsするようにするとよさそうです。