概要
今回は StatefulWidget つまり、「状態を持つウィジェット」について。
Flutterのバージョン
$ flutter --version Flutter 2.2.3 • channel stable • https://github.com/flutter/flutter.git Framework • revision f4abaa0735 (3 weeks ago) • 2021-07-01 12:46:11 -0700 Engine • revision 241c87ad80 Tools • Dart 2.13.4
StatelessWidget については以下を参照ください。
StatefulWidget は、その名前のとおり「状態を持つウィジェット」ですね。
どのUIフレームワークでも同じですが、状態が変化したらUIを更新するのが常です。
なので、状態を持つウィジェットというのは、何かのデータが変わったらUIを更新する必要がある部分に使います。
StatefulWidgetの公式ドキュメントは以下です。
ページの途中からパフォーマンスに関する記載がいっぱい書いてあります。このような記述が公式のドキュメントで記載されているのはとても素晴らしいですね。
でも、最初からパフォーマンスを意識して書こうとしても難しいので、今はそういうのは考えずに行きます。というか私がまだそこまで理解できていない。。
とりあえず、StatefulWidgetを使う上で覚えておくべきは以下の項目です。
- StatefulWidgetを継承したウィジェットにする
- Stateを継承したクラスを一緒に用意する
- StatefulWidgetまたはStateの中で
setState()
を呼ぶと State の build メソッドが呼ばれてUIを更新できる- initStateメソッドでデータの初期化
- disposeメソッドでデータの後始末
- buildメソッドでUIを構築
サンプル
UIを勉強するときに、データを変化させていくサンプルでちょうどいいのが時計さんです。
flutter create
すると出力されるサンプルもいいのですが、データが変わったら自動でUIが変化していく方が「動いてる感」が出て個人的に好きです。
main.dart
import 'package:flutter/material.dart'; import 'app.dart'; void main() { runApp(App()); }
app.dart
import 'package:flutter/material.dart'; import 'screens/clock_screen.dart'; class App extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Basic-03 StatefulWidget', theme: ThemeData.dark(), home: ClockScreen(), ); } }
screens/clock_screen.dart
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; /// [StatefulWidget]を継承したウィジェット /// /// [StatefulWidget]を継承した場合[createState]メソッドをオーバーライドする /// 必要がある.このメソッドからは自身に対応する[State]オブジェクトを生成して返す. class ClockScreen extends StatefulWidget { @override _ClockScreenState createState() { return _ClockScreenState(DateTime.now()); } } /// [ClockScreen]に対応する[State]オブジェクト /// /// このクラスで状態管理を行いながらUIを処理する. /// /// 主に利用する親クラスのメソッドは以下 /// /// - initState /// - dispose /// - build /// /// [setState]を呼び出すと、buildメソッドが呼び出される. /// なので、UIを反映したくなったら[setState]を呼び出せば良い. /// [setState]の引数にコールバックを渡すことができるので /// この中でUI変更に関わる値を変更する. /// class _ClockScreenState extends State<ClockScreen> { DateTime dt; late DateFormat _formatter; late Timer _timer; _ClockScreenState(this.dt); @override void initState() { _formatter = DateFormat("HH:mm:ss"); // 1秒毎に着火するタイマーで setState を呼び出して UI を更新 _timer = Timer.periodic(Duration(seconds: 1), (t) { setState(() { // このコールバックの処理が終わると build メソッドが呼び出される dt = DateTime.now(); }); }); super.initState(); } @override void dispose() { if (_timer.isActive) { _timer.cancel(); } super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Text( _formatter.format(dt), style: Theme.of(context).textTheme.headline2, )), ); } }
libディレクトリの下は以下のような感じ。
実行すると以下のようになります。
何の変哲もなくチクタクと更新しているだけですが、状態が更新されて (setState() が呼ばれて)、UIが再描画されて (build() が呼ばれて) いることがわかります。
参考情報
Flutter は本家のドキュメントだけでなく、YouTube上での動画も沢山用意されているので、リソースには困りませんね。めっちゃ分かりやすいです。
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場