動かして覚える山

エンジニアリング関連のことについて色々書いていきます。これは、自分が何ができるかを外部に公開すること。アウトプットの場にすること。他のエンジニアの参考になるものを投稿すること。自分用のメモとしてなどを目的として書いています。ですので、投稿の頻度や質は今の所まばらです。

flutter 最小コードから理解を深めてみた

flutterを理解するのに、最小のコードに肉付けしていくことで理解が深まったので、記事にしてみる。 早速以下が、最小コードだ。

title:main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(
      Text(
        "Hello World",
        textDirection: TextDirection.ltr)
  );
}

f:id:yama_shu99:20200219013758p:plain:w100

見ずらいけど、左上の時刻の部分に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")
      )
  );
}

f:id:yama_shu99:20200219013846p:plain:w100

エラーが出ずにコンパイルできる。

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"),
    );
  }
}

f:id:yama_shu99:20200219013846p:plain:w100

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"),
      ),
    );
  }
}

f:id:yama_shu99:20200219013851p:plain:w100

この、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'),
        ),
      ),
    );
  }
}

f:id:yama_shu99:20200219013855p:plain:w100

なるほど、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を持つありがたみが、これでは全くわからないので、それは、これから理解していこうと思う。