flutter 最小コードから理解を深めてみた
flutterを理解するのに、最小のコードに肉付けしていくことで理解が深まったので、記事にしてみる。 早速以下が、最小コードだ。
title:main.dart
import 'package:flutter/material.dart'; void main() { runApp( Text( "Hello World", textDirection: TextDirection.ltr) ); }
見ずらいけど、左上の時刻の部分にHelloWorldと表示されている。 Text(...)の部分はnew Text(...)のようにも書いて良い。どうやらDart2ではnewを省略できるようになったらしい。 Textの引数としてtextDirectionというのがある。これを外すと以下のようなエラーとなる。
title:console
I/flutter (22688): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ I/flutter (22688): The following assertion was thrown building Text("Hello World"): I/flutter (22688): No Directionality widget found. I/flutter (22688): RichText widgets require a Directionality widget ancestor. I/flutter (22688): The specific widget that could not find a Directionality ancestor was: I/flutter (22688): RichText I/flutter (22688): The ownership chain for the affected widget is: "RichText ← Text ← [root]" I/flutter (22688): Typically, the Directionality widget is introduced by the MaterialApp or WidgetsApp widget at the I/flutter (22688): top of your application widget tree. It determines the ambient reading direction and is used, for I/flutter (22688): example, to determine how to lay out text, how to interpret "start" and "end" values, and to resolve I/flutter (22688): EdgeInsetsDirectional, AlignmentDirectional, and other *Directional objects.
Directionality widgetがないと怒られる。 テキストを書く方向がわからないからのよう。 TextはRichTextを継承していて、RichTextはDirectionalityWidgetを親に持たなければなならない。ただ、このコードでは、Text自体にDirectionを指定してDirection(方向)を与えている。ここでは最小のコードにしたかったため、Directionを指定しているが、普通はMaterialAppやWidgetsApp widgetを親に指定することで、方向をRitchTextに与えるらしい。ということで書いてみる。
title:main.dart
import 'package:flutter/material.dart'; void main() { runApp( MaterialApp( home: Text("Hello World") ) ); }
エラーが出ずにコンパイルできる。
runAppにはWidgetを指定しなければならない。 TextはStatelessWidgetを継承しているため、Widgetである。 ここで指定しているMaterialAppもStatefulWidgetを継承しているため、Widgetである。
title:main.dart
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( home: Text("Hello World"), ); } }
StatelessWidgetは状態を持っていないWidget。StatefulWidgetは逆に状態を持っているWidget。 StatelessWidgetを継承するクラスはをWidgetを戻り値としたbuild関数をオーバーライドする必要がある。 この戻り値のWidgetが画面に描画されるみたいな作りになってるみたい。 なるほど、なんとなくわかってきた。
title:main.dart
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'My First App', home: Center( child: Text("Hello World"), ), ); } }
この、CenterもWidgetだ。ここまでくれば、WidgetTreeによってUIが構成されるんだなと感覚で理解できてきた。
title:main.dart
import 'package:flutter/material.dart'; import 'package:english_words/english_words.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'My First App', home: Scaffold( appBar: AppBar( title: Text('Welcome to Flutter'), ), body: Center( child: Text('Hello World'), ), ), ); } }
なるほど、ScaffoldってのはこういうWidgetなんやね。
ここからは、公式サイトのGetStartedと同じなんやけど、statefulwidgetはこんなふうなコードになる。
title:main.dart
import 'package:flutter/material.dart'; import 'package:english_words/english_words.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'My First App', home: Scaffold( appBar: AppBar( title: Text('Welcome to Flutter'), ), body: Center( child: RandomWords(), ), ), ); } } class RandomWordsState extends State<RandomWords> { @override Widget build(BuildContext context) { final wordPair = WordPair.random(); return Text(wordPair.asPascalCase); } } class RandomWords extends StatefulWidget { @override RandomWordsState createState() => RandomWordsState(); }
StetefulWidgetを使うには、StateとStateのインスタンスを作成するStatefulWidgetを作成する必要がある。StatefulWidget自身は普遍で、可変の値をStateで持つ作り。
Stateを持つありがたみが、これでは全くわからないので、それは、これから理解していこうと思う。