LoginSignup
20
19

More than 5 years have passed since last update.

Flutterの動的ページを作る基礎的なお話

Posted at

はじめに

何かを作るのにはやっぱり動的なページだなということで勉強したことのまとめです。

環境

Android Studio
Flutter 1.0

StatefulWidget

Flutterは動的なWidgetを作成するために状態を持つStatefulWidgetを使用することがベースとなります。(他のWidgetを使うこともあるようなので、初期の勉強としてはです)

ただしStatefulWidgetをそのまま大元の子供としてエラーとなってしまうようです。

import 'package:flutter/material.dart';

void main() => runApp(App());

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MyApp();
  }

}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return TestState();
  }
}
I/flutter (11861): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter (11861): The following assertion was thrown building MyApp(state: TestState#0a289):
I/flutter (11861): MediaQuery.of() called with a context that does not contain a MediaQuery.
I/flutter (11861): No MediaQuery ancestor could be found starting from the context that was passed to MediaQuery.of().
I/flutter (11861): This can happen because you do not have a WidgetsApp or MaterialApp widget (those widgets introduce
I/flutter (11861): a MediaQuery), or it can happen if the context you use comes from a widget above those widgets.
I/flutter (11861): The context used was:
I/flutter (11861):   Scaffold(dirty, state: ScaffoldState#18d75(lifecycle state: initialized, tickers: tracking 1
I/flutter (11861):   ticker))

正常に動作させるためにはいくつか方法があるようですが、最初はMaterialAppを使って覚えていくのが一番楽そうです。
WidgetAppもいけるようですが、builderの概念がまだよく分かってないので、いったん置いておきます。
ということでMaterialAPPを使って何かしら表示させることができたコードが以下となります。

class App extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: MyApp());
  }

}

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return TestState();
  }
}

class TestState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Demo"),
      ),
      body: Center(
        child: Text('Stateful Demo'),
      ),
    );
  }

}

State

StatefulWidgetを継承したクラスではcreateStateを実装しState<T>を返却する必要があります。
State自体はWidgetを返却するため、ここで状態で変化するWidgetを作成します。

今回はButtonを作って押したらその日時が表示されるような変化を起こす実装をしてみます。

Stateの作成方法としては基本はWidgetを作成するため、そこは特に違いがありません。
違いとしては状態が変更されるというトリガーがあるのと、そのトリガーを持って状態を変化させる実装する点にあります。

状態変化時の動きについてはsetStateに変化時に動作するべき関数を渡すことで実現します。setStateは引数にvoidが戻り値となるfunctionを渡す必要があるため、この内部で何かしらの副作用を与える形となります。
setState外部で状態を変更して渡すという訳ではないので、その点は注意が必要です。

トリガーはButtonなので、Widget CatalogにあるBasicsにあったRaisedButtonを使用します。
各種ボタンには押された際に動作するonPressedが用意されているため、ここに引数なしかつvoidが戻り値となるfunctionを渡すことで押下時の動作を指定することができます。
今回はここにsetStateを実装したfunctionを渡すことでトリガーとなります。
setStateonPressedの引数が違うため、onPressedに直接実装できないため、何かしらでラッピングさせる必要がある点に注意ください。

そうして出来たStateが以下のコードとなります。
これを実行して右下にあるボタンを押すと真ん中のテキストが現在日時で更新されていきます。

変数の文字列展開は$変数とすればできるので、今回は変数に日時の文字列を入れてその文字列を展開することで実現しています。

class TestState extends State<MyApp> {
  String _dateText = DateTime.now().toString();

  void _updateDateText() {
    setState(() {
      _dateText = DateTime.now().toString();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Demo'),
      ),
      body: Center(
        child: Text('$_dateText'),
      ),
      floatingActionButton: RaisedButton(
        onPressed: _updateDateText,
        child: Text("Button"),
      ),
    );
  }
}

動的ページを作るためのまとめ

StatefulWidgetStateの組み合わせで動的ページを作成できることが分かったので、いったんここで動的なページを作るためのまとめを書きます。
ここでは上で作ったような最小限な構成とします。

Widget構成は以下画像のようになり、実装としてはMaterialApp配下の組み立てとなることが多くなりそうです。
状態についてはStatefulWidgetを間にかませてState<T>配下に設定したイベントを検知して変更するロジックを組むことになります。
状態変更については副作用を与えることが前提となるため(現状わかっている範囲では)、メンバ変数の変更で対応していくことになります。

Untitled Diagram (2).png

20
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
19