Chapter 04

Day3: Flutterの概要, Widget, State

fastriver
fastriver
2021.02.13に更新

今回はこのくらいのができるくらいまでやります。

Hello, world!の説明

前回最後にFlutter WebのHello, worldをやったのでそれの説明からです。

大雑把に

  1. main関数
  2. runApp()
  3. MyApp.build()
  4. MyHomePage.createState()
  5. MyHomePageState.build()

のような順番で呼ばれていく

ファイル構成

dartのコードは./lib/に書く

./web/にあるものはindex.htmlなど普通のWebサイトに必要な物たち

./android/ ./ios/などはそれぞれのプラットフォーム専用のコードが書かれている。Flutterでは固有の呼び出しをうまく隠蔽してくれているためほとんど弄る必要がない。

全てはWidgetである

Flutterの画面を構成する全ての部品はWidgetというパーツである。Widgetどうしは入れ替えることが可能なため、自由なレイアウトが実現できる。

くわしく

下のページはCardというWidgetを並べてできている

Cardの中に配置されている画像や文字、ボタンはWidgetである

マクロに見るとCardたちのレイアウトもGrid Widgetであり、さらに画面全体もScaffold Widgetでできている

Flutterの呼び出し自体もMaterialAppというWidgetだったりする

これはCard Widget

右下に配置するのにAlign Widgetで囲んでいる

端から少し余白をとるのにもWidgetでMarginをとる

中に入っているアイコンや文字もWidgetである

このようにFlutterの世界では文字や画像からレイアウトや余白まで全てがWidgetでできているのだ

もちろん自分で新しいWidgetを作ることも可能

各Widgetについて

Widget Catalog(英語)

使いそうなWidgetがまとまってるページを見つけた

もうひとつ見つけた

使う雛形(これでmain.dartの中身を入れ替える)

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Web Training',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: 
    );
  }
}

Text

Text(
	"Hello, Flutter!",
	style: TextStyle(
		fontSize: 32.0,
		color: Colors.green
	)
),

DartPadで見る

最初に表示するテキストを引数に取る。

文字の装飾をしたい場合は名前付き引数のstyleにTextStyleを渡す

Button

RaisedButton(
	onPressed: () {
		//押された時はここが実行される
		print("Button Clicked!");
	},
	child: Text( //ここに渡したWidgetがボタンの中に表示される
		"Hello, Flutter!",
		//...
	)
),

DartPadで見る

child引数に中に入れたいWidgetを書く

onPressed引数に、押されたときの処理を書く

  • RaisedButton: 影のついたボタン
  • FlatButton: 文字だけのボタン
  • OutlineButton: 外枠のみのボタン

Center

Center(
	child: RaisedButton(
		//...
	)
)

DartPadで見る

child引数に取ったWidgetを中心にくるようにする

Column

Column(
	mainAxisSize: MainAxisSize.min,
    children: <Widget>[
        Text(
			"Click!",
			style: TextStyle(
				fontSize: 50.0
            ),
        ),
        Text(
            "↓",
            style: TextStyle(
            	fontSize: 30.0
            ),
        ),
        RaisedButton(
            onPressed: () {
                print("Button Clicked!");
            },
            child: Text(
                "Hello, Flutter!",
            	style: TextStyle(
                	fontSize: 32.0,
                	color: Colors.green
				),
            ),
        ),
    ],
)

DartPadで見る

children引数に取ったWidgetたちを縦に並べる(配列で渡す)

mainAxisSize: MainAxisSize.min,

この一行はColumnウィジェットの縦の長さを規定し、MainAxisSize.minだと中の要素と同じサイズまで縮む(デフォルトは縦いっぱいに広がる)

配列: 角括弧[]の中に複数のものをコンマ,区切りで並べたもの

Container(Advanced)

Container(
    width: 300.0,
    height: 200.0,
    color: Colors.orange,
    margin: EdgeInsets.all(8.0),
    padding: EdgeInsets.all(8.0),
    child: RaisedButton(
        onPressed: () {
            print("Button Clicked!");
        },
        child: Text(
            "Hello, Flutter!",
            style: TextStyle(
                fontSize: 32.0,
                color: Colors.green
            ),
        ),
    ),
),

DartPadで見る

中のWidgetの大きさ・背景色・余白等を管理する

レイアウトの話

StatefulWidgetとsetState()とメンバ変数

Hello, worldでは詳しく触れなかったが、Flutterは画面更新の仕組みの一つとしてStatefulWidgetというものを用意している。

class MyHomePage extends StatefulWidget {

extendsはこのクラスがStatefulWidgetの役割を持つことを定めている(継承)。

StatefulWidgetはその名の通りState(状態)を持つWidgetである。

アプリ界隈の人とかはライフサイクル管理を知っているだろうが、FlutterではStatefulWidgetでライフサイクルを管理する

今講習会ではほとんど扱わない

setState(() {})

StatefulWidgetの中で

setState(() {
	title = "タイトルを変更!";
})

みたいにsetStateと一緒に変数を書き換えるとその変数を使っているWidgetの見た目をいい感じに更新してくれる!

class _MyHomePageState extends State<MyHomePage> {
  String title = "Click!"; ////////////////////////////////追加!

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Text(
              title, ///////////////////////////////////////変更!
              style: TextStyle(
                fontSize: 50.0
              ),
            ),
            Text(
              "↓",
              style: TextStyle(
                fontSize: 30.0
              ),
            ),
            RaisedButton(
              onPressed: () { //////////////////////////////変更!
                setState(() {
                  title = "クリックされた!";
                });
              },
              child: Text(
                "Hello, Flutter!",
                style: TextStyle(
                  fontSize: 32.0,
                  color: Colors.green
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

DartPadで見る

便利

何が起こっているのか

  1. 変数を書き換える
  2. setStateを呼ぶ
  3. 呼ばれたStatefulWidgetは変数の変更を知る
  4. build関数を実行して画面を書き換える

実際はRenderTreeとか見ながら差分を見て更新部分だけrebuildしたり頑張っている

mono氏の記事が分かりやすいので興味のある人は読んでみては

おしまい

課題(物足りない人向け)

  • カウンターを作ってみる
  • ボタンを並べてキーボードみたいなものを作ってみる