最近Flutterをいじり始めました。Scoped Modelを利用するとスッキリ書けるので、そのコードを書いたときの画面遷移時に具体的にどうコードを書くとうまくいったかをレポートします。
[Scoped Model 初めて聞いた方へ]Scoped Model とは
公式のパッケージサイトは下記です。
基礎原理の解説について下記記事が参考になりました。
自分の言葉で書くと、数値や文字列の処理部分とデザインテンプレート部分をModel定義をすることで綺麗に分離ができます。あと、このパッケージは、GoogleのFlutter開発チームが提供してくれているVeggie Seasonsというアプリのコードにも採用されていたので、自分もやってみようと思いました。Veggie Seasonsのコードは以下です。
ページ遷移時の試行錯誤時のエラー解決で得た知見
今回はこちらを共有したいのです。Scoped Modelを使わない場合と比較できるように書いてみました。
#main.dart
//1:route定義をMaterialAppのところで行って、
void main() {
runApp(MaterialApp(
title: 'Demo',
initialRoute: '/',
routes: {
'/': (context) => FirstScreen(),
'/second': (context) => SecondScreen(),
},
));
}
//2:↓最初のページに当たるFirstScreen部分のStatelessWidget記述です。
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('Demo'),
),
body: Center(
// 中略
child: RaisedButton(
padding: EdgeInsets.all(12.0),
shape: StadiumBorder(),
child: Text(
"次のページへ",
style: TextStyle(fontSize: 20.0, color: Colors.white),
),
color: Colors.green,
onPressed: () {
Navigator.pushNamed(context, "/second");
//3:↑で次のページ"SecondScreen()"へ移動クラス生成です。
},
),
//次の画面(SecondScreen)
class SecondScreen extends StatelessWidget {
//以下略SecondScreenの表示内容などが書かれています。
}
↑これをScoped Model 活用して記述する際、
下記のように書くとうまくいきました。
#main.dart
import 'model.dart';
/*
↑model(今回はDemoModelという名称です)を別ファイルで定義しました。
このmodelそのものの部分の解説は、
ページ遷移の解説に戻るまでにかなり時間がかかるので割愛します。
※本記事前述の解説などの参考になる記事が複数存在しますので、ご覧ください。
*/
import 'package:scoped_model/scoped_model.dart';
// scoped_modelのパッケージをインポートします。
DemoModel demoModel = DemoModel();
//modelを生成しておきます。
void main() {
runApp(MaterialApp(
title: 'Demo',
home: ScopedModel<DemoModel>(
model: demoModel,
child: new FirstScreen()
)
));
}
/*
route指示部分がごっそり無くなっています。書いてみるとエラーになりました。
遷移時に各ボタンなどの実行時のコードに
Scoped Modelの子孫のクラスとなる次のページのクラス生成を指示することになります。
*/
//最初の画面(FirstScreen)
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text('Demo'),
),
body: Center(
// 中略
child: RaisedButton(
padding: EdgeInsets.all(12.0),
shape: StadiumBorder(),
child: Text(
"次のページへ",
style: TextStyle(fontSize: 20.0, color: Colors.white),
),
color: Colors.green,
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute<Null>(
settings: const RouteSettings(name: "/second"),
builder: (BuildContext context) {
return MaterialApp(
home: ScopedModel<DemoModel>(
model: quizBrainModel,
child: new SecondScreen(),
),
);
}
),
);
/*
↑ScopedModelを使わない場合、
Navigator.pushNamed(context, "/second");となっていた部分です。
*/
},
),
//次の画面(SecondScreen)
class SecondScreen extends StatelessWidget {
SecondScreen();
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text("Second Page"),
),
body:
//中略
new ScopedModelDescendant<DemoModel>(
builder: (context, child, model) =>
new Row( children: model.getSomeList())
)
/*
↑このページは、Scoped Model子孫クラスなので
new ScopedModelDescendant<Model名称>で
メソッドや変数が呼び出せます。
例としてmodelで指定しておいた、
特定のListを呼び出すメソッドを書いています。
*/
参考になればと思います。他にも書き方があるかもしれません。ご指摘などあればコメントいただければと思います。