Flutter Navigator 2.0 による画面遷移の状態管理
こんにちは、カシオ入社3年目のIです!
今回は、最近知ったFlutterアプリ開発での画面遷移管理方法の進化について共有したいと思います。
2024年9月現在、Flutter入門のサイトでは画面遷移のチュートリアルとしてNavigatorのPush & Popを紹介されているものが多いです。
そのため、現在も継続してPush & Popを用いた画面遷移を行っている方が多いのではないか思います。私もその一人でした。
ある時、業務でMVVMを意識したFlutterでのアプリ実装に取り組んだ際に、いつも通りPush & Popを利用して画面遷移を実装しようとしました。
しかし、画面の状態をViewModel管理するMVVMにおいて、Push & Popでは画面の状態を管理できていないと思いました。そこで画面遷移の状態もRiverpodで管理できるような実装できないかと調査を行ったところ、Navigator2.0で状態管理型の画面遷移が可能となっていたことがわかりました。
今回はそのNavigator2.0で可能となった状態管理型の画面遷移について紹介したいと思います。
まず、従来のPush & Popのイメージを示します。
従来はPushで画面の上に新たなページを重ね、Popで一番上のものを取り除くイメージになっています。(この方法はNavigator2.0でも使用可能です)
次に状態管理型のイメージです。
pagesというMaterialPageのリストをNavigatorに設定することで、pagesの中の状態が画面表示となります。
Navigatorにpagesを指定する方法は、以下になります。
return Navigator(
pages: pages,
onPopPage: (route, result) {
if (!route.didPop(result)) {
return false;
}
navigatePagesNotifier.pageBack();
return true;
},
)
これでpagesの状態が、画面表示となります。
次に、pagesの中身の変更についてです。
flutterの画面は、値の中身だけ変更しても画面には反映されません。反映させる場合は、StatefulWidgetの場合setStateを呼ぶ必要があります。
ここでRiverpodを利用します。flutterの状態管理ライブラリであるRiverpodでは、ConsumerWidgetを用いて監視した値が変更されたタイミングで画面を更新する仕組みになっています。
pagesをRiverpodで監視して、NavigatorをConsumerWidgetでreturnすることによってpagesの変更時に自動で画面が更新されます。
また、Riverpodで値を監視している際はNotifierというものを作成し、Notifierで値を更新する必要があります。(Riverpodの話は、また別の話になりますので省略します。)
ページを更新するNotifierの例は、以下になります。
void navigateNewPage(MaterialPage newPage) {
List<MaterialPage> newState = List.from(state.pages);
newState.add(newPage);
state = state.copyWith(pages: newState);
}
newState は、pagesがimmutableな変数として定義されているためcopyWithで値を更新しています。
呼び出しは、こんな感じ。
navigationPageListNotifier.navigateNewPage(newPage)
これでnewPageに遷移したいページを入れれば、pagesの末尾に画面が追加され画面遷移できます。実質Pushと同じですね。
このままではPush & Popと同様ですが、この状態管理型ではNotifierの定義次第でpagesの中身を自由に変更できるため、Push & Popよりも自由で万能な画面遷移が実現可能です。
また、MVVMの実装としてもpagesの状態をViewModelで管理できているため良い形となります。
今回は、Navigator2.0を自分でアレンジして実装する方法を紹介しましたが、goRouterなどのNavigator2.0を理解していなくても簡単に使えるようにしてくれているパッケージなどもあります。
個人的には自分で状態を管理したいため今回紹介した方法がおススメですが、そういったパッケージを利用するのも良いでしょう。
■関連記事
Flutterアプリ開発における「状態管理」とは
【カシオのソフトウェア採用についてはこちら】