わんぱく Flutter! 第三回 ページ移動をしてみよう!
前回は、動作確認用のアプリケーションに、色々な Widget を追加してみました。その他の基本的な動作と言えば、「ページ移動」ではないでしょうか。今回は、ページ移動を行ってみます。 Flutter のページ移動は、前回作成した動作確認用のアプリケーションと同様、新しい xxxx.dart ファイルに、ページを作成する class を記述して、呼び出し元 class から、Navigator.push() API を呼ぶだけです。それでは早速、やって行きましょう。
1. Navigator.push によるページ移動
まず、新しい xxxx.dart ファイルを作成します。どのような方法でも宜しいのですが、android studio を使っているなら、左ウィンドウの project - lib を右クリックして、new - dart file から "secondpage.dart" を作成します。作成したら、下記コードを記述して下さい。
import 'package:flutter/material.dart';
class secondpage extends StatefulWidget {
secondpage({Key key}) : super(key: key);
@override
_secondpage createState() => _secondpage();
}
class _secondpage extends State<secondpage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Page"),
),
body: Center(
child: Text("")
),
);
}
}
細かい説明は今回は飛ばして、Flutter の新しいページは、このフレームワークで書くのだと理解してください。 class が二つあるのが解ると思います。ひとつ目が、呼び出し側から見た class 名を記述します。そして、ふたつ目の class があると思います。違いは解るでしょうか。 ー
そう、 class 名の頭に "_" が付いています。 前回も簡単に説明してありますが、Flutter は頭に "_" を付けると、外部からは参照できない扱いとなります。
また、よく目立つ "return" の直ぐ下に "appBar:" と言う記述があります。これは、アプリケーションの上に表示されるバーです。これを付けておくと、画面遷移をした後に、戻るボタン "←" が自動的に表示されて便利です。特に理由がなければあって問題ないでしょう。
そうしたら、呼び出し元である main.dart に、Navigator.push() を追加します。ボタンを押した時にページ移動させたいのですから、ElevatedButton() の onPressed に記述します。大括弧の前に空の括弧があったり、少し妙ちくりんな記述ですが、ここは、こう書くのだと思って下さい。これも、dart のシンタックスシュガー(省略した表記法)です。解りにくいですね。
ElevatedButton(
child: Text("Next"),
onPressed: (){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => secondpage()),
);
}
)
Navigator.push() の引数の MaterialPageRoute() にある secondpage() が、今回新しく作ったページの class 名です。そして、新しく作った secondpage.dart を呼び出すのですから、main.dart の先頭にある import に、このファイルを加えておきます。
import 'package:flutter/material.dart';
import 'secondpage.dart';
void main() {
runApp(MyApp());
}
これで準備完了です。android studio を使っているのであれば、文法エラーなどには、赤い波線のアンダーラインが付くので、そこを直してから実行します。実行したら、中央に ElevatedButton() が表示されているはずです。言うまでもなく、そのボタンを押すと、ページ移動するという事です。
はい。無事、ページ移動しました。ページを戻る際は、上の appBar の矢印を利用します。
2. 引数による値渡し
次に必要になってくるのは、恐らく、引数による値渡しでしょう。ページ間で、何らかのデータのやり取りがあるのが普通です。これは、MaterialPageRoute() にある class の引数として渡します。例えば、"メッセージ" という文字列を、次のページの message と言う変数へ渡すなら、以下のように記述します。
Navigator.push(
context,
MaterialPageRoute(builder: (context) => secondpage( message: "メッセージ")),
);
そして、受け取り側である secondpage class では、引数として受け取った値を、this.message へ格納することを指定します。
import 'package:flutter/material.dart';
class secondpage extends StatefulWidget {
secondpage({Key key, this.message}) : super(key: key);
final String message;
@override
_secondpage createState() => _secondpage();
}
これで message を受け取ることができます。確かに受け取ることができたことを確認するために、Text Widget に表示してみましょう。
body: Center(
child: Text( widget.message )
),
受け取った message を、下の class の Text Widget で使うには、上記の通り、widget に属する変数としてアクセスします。ちょっと込み入ってきますので、詳しい説明は後回しにしますが、上の class を、下の class が継承しているので、上の class で受け取った引数は、widget のプロパティとなります。
それでは実行してみましょう。
引数が複数ある場合は、カンマで繋げて記述します。
class secondpage extends StatefulWidget {
secondpage({Key key, this.message1, this.message2}) : super(key: key);
final String message1;
final String message2;
@override
_secondpage createState() => _secondpage();
}
呼び出し側も同様です。
Navigator.push(
context,
MaterialPageRoute(builder: (context) => secondpage( message1: "メッセージ", message2: "メッセージ2")),
);
3. Global 変数を使用した値の参照
と、ここまでは行儀のよいプログラムでの、正攻法による値渡しですが、些か面倒です。私は、非常に面倒に感じているので、global 変数を使用することをお薦めします。
例えば、main.dart の先頭、import が記述されている直ぐ下に、プログラム全体で共有したい値を記述しておくと、他の xxxx.dart ファイルで記述している class からも参照することができます。
import 'package:flutter/material.dart';
import 'secondpage.dart';
String g_message = "広域メッセージ";
void main() {
runApp(MyApp());
}
これは、dart プログラミング言語における変数の有効範囲(スコープ)を利用した値の共有方法です。ここで、g_message がプログラム全体で共有したい変数です。
import 'package:flutter/material.dart';
import 'main.dart';
secondpage.dart の先頭の import にも import 'main.dart'; を追加しておきます。そして、試しに Text Widget で表示させてみて下さい。
body: Center(
child: Text( g_message )
),
flutter の値渡しは、こっちの方がいいんじゃない? とても簡単で、widget.xxxx の記述もいりません。それでは、実行してみましょう。
今回は、ページ移動と、値渡しについて解説しました。
以上