はじめに
この記事では、Navigator Widgetについて解説します。(以下、Navigatorとします)
以下の2部構成です。
- Navigatorの使い方
- Navigatorの仕組み
ただし、この記事では、遷移時のアニメーションの作り方については触れていません。ご注意ください。
この記事のサンプルコードは以下のページに置いています。
https://github.com/HeavenOSK/basic_navigator
Navigatorとは
NavigatorはFlutterでページ遷移を実装する際に使用するWidgetです。
Navigatorの使い方
Navigatorの使い方について解説します。
解説する内容は、以下の通りです。
- 進む遷移をして、戻る遷移を行う
- 戻る遷移の直後に、処理を行う
- 戻る遷移の際に、値を受け取る
1.遷移して戻る
最もシンプルで、よく用います。
ボタン押下など、ユーザ操作のコールバックに Navigatorの処理を書きます。
進む遷移ではpush
メソッドを、戻る遷移ではpop
メソッドを用います。
RaisedButton(
child: Text('Next'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return SecondPage();
},
),
);
},
)
RaisedButton(
child: Text('Back'),
onPressed: () {
Navigator.of(context).pop();
},
)
サンプルコードでは、push
メソッドの引数としてMaterialPageRoute
を指定しています。これは、遷移時にMaterialDesignに則ったアニメーションを行うための指定です。
MaterialPageRoute
をCupertinoPageRoute
と書き換えれば、iOS風のアニメーションで遷移します。
またMaterialPageRoute
では、builder
プロパティの返り値として、SecondPage
を指定しています。これは遷移先のページの指定です。
SecondPage
をThirdPage
と書き換えれば、ThirdPage
への遷移になります。
2. 戻る遷移の直後に、処理を行う
push
メソッドの前にawait
キーワードを書きます。
(コールバックの先頭にasync
キーワードを書くのを忘れないようにします)
push
メソッド以下の処理は、戻る遷移の後実行されるようになります。
以下のサンプルコードでは、戻る遷移の直後にshowDialog
メソッドが実行されます。
RaisedButton(
child: Text('Next'),
onPressed: () async {
await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return SecondPage();
},
),
);
showDialog(
context: context,
builder: (context) => SampleDialog(),
);
},
),
3. 戻る遷移の際に、値を受け取る
遷移時に、フォームの入力情報などを受け渡す際に使います。
前項で紹介した「戻る遷移の直後に、処理を行う」ことが可能なのは、push
が遅延処理を行うメソッドだからです。
push
メソッドの返り値はFutureクラスで、遷移時の値の受け渡しに用います。
push
メソッドの前にawait
キーワードを書き、変数に代入することで、戻る遷移の際にpop
メソッドから渡された値を用いることができます。
以下では、受け取った文字列をshowDialog
で表示しています。
RaisedButton(
child: Text('Next'),
onPressed: () async {
final result = await Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return SecondTextInputPage();
},
),
);
if (result != null) {
final contentText = 'I received ' + result + ' !';
showDialog(
context: context,
builder: (context) {
return SampleDialog(
contentText: contentText,
);
},
);
}
},
)
pop
メソッドでは、受け渡したい値を引数に指定します。
以下のサンプルコードでは、テキストフィールドで入力された文字列をpop
メソッドの引数で渡しています。(複数の値を受け渡しすることも可能です。)
String inputValue = '';
TextField(
onChanged: (value) {
inputValue = value;
},
onEditingComplete: () {
Navigator.of(context).pop(inputValue);
},
)
まとめ
Navigatorの基本的な使い方を見ました。
「Navigatorの使い方」は以上です。
2. Navigatorの仕組み
ここから先は、Navigatorの仕組みについて解説します。
Flutter の公式ドキュメントの Navigator のページの冒頭には、以下のように書いています。
A widget that manages a set of child widgets with a stack discipline.
https://docs.flutter.io/flutter/widgets/Navigator-class.html
スタック規律を使用して子ウィジェットのセットを管理するウィジェット。(訳:Google翻訳)
つまり、Navigatorは、「スタックの仕組みを使って、子Widgetの集まりを管理する Widget」 です。
スタックは「後入れ先出し(一番最後に入れたものを出す)」のデータ構造です。
よって、「一つ前に訪れたページに戻る」 というページ遷移の実装に適しています。
スタック (wikipedia)
https://ja.wikipedia.org/wiki/%E3%82%B9%E3%82%BF%E3%83%83%E3%82%AF
ところで、Flutterに触れたことがある人なら、スタックと聞いて思い出すWidgetがあると思います。
そうです。Stack Widgetです。
Stack
Stack Widgetは複数のWidgetを重ねて表示する際に使用する Widget です。(以下、Stack とします)
Stack
のchildren
プロパティにWidgetのリストを指定することで、複数のWidgetを重ねて表示できます。
以下の例では、BottomWidget
、TopWidget
が重ねて表示されます。
Stack(
children: <Widget>[
BottomWidget(),
TopWidget(),
],
)
Navigatorによる遷移は、データ構造としてのスタックだけではなく、このStack Widgetを用いて実現されています。
遷移時の処理の流れ
遷移時にStack上にWidgetを重ねる処理は、Overlay Widgetが担当します。
「Navigatorの使い方」で用いたサンプルコードを再掲します。
以下のサンプルコードでは、FirstPage
からSecondPage
への遷移を行っています。
class FirstPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: RaisedButton(
child: Text('Next'),
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return SecondPage();
},
),
);
},
),
);
}
}
上記のサンプルコードでpush()
・pop()
を行ったと仮定して、処理の流れを追ってみます。
※以下、「Overlayが管理するStack」を、単にStackと書きます。
FirstPageからSecondPageへpush()を行う時
(0.StackにFirstPage
のみ追加されている状態)
1.Stackの最上部にSecondPage
を追加して、画面外に配置する
2.SecondPage
をアニメーションして、画面前面に移動させる
3.アニメーション終了後、StackからFirstPage
をoffstageに追加する
(※offstageは、Overlayの内部で使われている、現在描画する必要はないが、将来描画する予定があるWidgetのリストです)
SecondPageからFirstPageへpop()を行う時
(0.StackにSecondPage
のみ追加されている状態)
1.StackのSecondPage
の下層にFirstPage
追加する
2.画面前面のSecondPage
をアニメーションして、画面からはずれるように移動させる
3.アニメーション終了後、StackからSecondPage
を除外して、Overlayの管理からも除外する
(※現在描画する必要がなく、将来描画する予定もないWidgetはOverlayの管理から除外されます)
基本的には以上の流れで、Navigatorによる遷移が行われます。
このような管理を行うことで、描画の負荷を下げています。
まとめ
Stack
の観点から、Navigatorによる遷移の仕組みを見ました。
「Navigatorの仕組み」は以上です。
おわりに
ここまで読んでいただき、ありがとうございました。
誤っている点や分かりにくい点にお気づきになられましたら、お手数ですがTwitterアカウントまでお願い致します。