Flutterの基礎

Flutterについて基本的なところのまとめ
自分用のメモ

（参考）[Flutter by Example](https://flutterbyexample.com/)
（参考）[DroidKaigi2018で発表したFlutterアプリの話のスライド補足](http://konifar.hatenablog.com/entry/2018/02/11/081031)

## Dart全般
* Javaのようにクラスをインスタンス化してメソッドを呼び出さなくてもいい
* オーバーライドメソッドはどのタイミングで呼ばれるか不明

## Widgetについて
* Widgetはreactにもある概念
* newされて利用される（2018年時点ではnewを省略するのが主流らしい）
* Widgetクラスは必ず他のWidgetを返すbuildメソッドをもつ
* buildメソッドはWidgetの代わりにテキストを返すこともできる
* Widgetの入れ子でflutterは構成される
* 表示もアクションもバックグラウンドもCSSもWidgetの入れ子で表現する

## StatelessWidget
* StatelessWidgetを継承した1つのクラスで構成されている
* StatelessWidgetはbuildメソッドを持ち、Widgetもしくはテキストを返す
* 返すWidgetはStatefulWidget（MaterialAppとか）でもOK
* 「state(状態)」の概念がないため、動的に変化しないWidget

## StatefulWidget
* Widgetにstateの概念をいれて拡張したもの
* stateが変化したときに再描画を指示するメソッドが組み込まれている
* StateクラスとWidgetクラスの2つのクラスで構成されている
* StatefulWidgetはbuildメソッドを持たず、createStateメソッドを持ち、これがStateクラスを返す
* StatefulWidget自体はシンプルな構造で複雑な処理等はStateクラスで持つ
* Stateクラスで機能的なメソッドを実装する
* Stateクラスはbuildメソッドをもち、Widgetを返すときに定義したメソッドを  
  アクションとして組み込める  
* returnできるWidgetはいくつも種類があり、TextやImage、TextInput、Scaffold等
* ScaffoldはルートページとなるデザインWidgetで基本的なレイアウト構造

## StatefulWidgetのメソッド構成
### Widgetクラス
#### createState()
　ビルド後に呼ばれるメソッドで必須
　型はState

### Stateクラス
#### initState()
　最初に一度呼ばれる
　Widgetツリーの初期化を実行
#### didChangeDependencies()
　initState()呼び出し直後に呼ばれる
　Widgetツリーの変更を要素に通知する
#### build()
　didChangeDependencies()呼出し後にしか呼ばれない
　複数回呼ばれる
　Widgetツリーを置き換える
#### didUpdateWidget(Widget oldWidget)
　リビルド時のinitState()的な位置づけ
#### setState()
　任意で呼べるメソッド
　Widgetツリーを再構成して、変更を反映させる
　簡単な変数の代入だけでなく非同期処理でも使える
#### deactivate()
　StateをWidgetツリーから削除する
　滅多に使わないらしい
#### dispose()
　Stateを永続的に削除する
　画面をおとすときやストリーム停止で使うらしい

## サンプルソース

```dart:main.dart
// メイン関数、実行時に最初に呼ばれる
// runAppメソッドは引数のwidgetをスクリーンにアタッチする
// runAppメソッドの引数のWidgetが画面いっぱいに表示される
void main() => runApp(new MyApp());

// runAppの引数として生成され、最初にインスタンス化されるクラス
class MyApp extends StatelessWidget {
  // このメソッドでリターンしたWidgetがメイン画面になる
  @override
  Widget build(BuildContext context) {
    // MaterialAppで画面のテーマ等を設定できる
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.red,
      ),
      home: new MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

// MaterialAppにセットされるホーム画面
class MyHomePage extends StatefulWidget {
  // コンストラクト
  MyHomePage({Key key, this.title}) : super(key: key);

  // 定数定義
  final String title;

  // アロー関数を用いて、Stateを呼ぶ
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

// Widgetから呼ばれるStateクラス
class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  List<String> _data;

  // メソッドの定義
  void _incrementCounter() {
    // 画面の再描画を実行する
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    // デザインWidget
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text(
              'You have pushed the button this many times:',
            ),
            new Text(
              _data.length.toString(),
            ),
            new Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: new FloatingActionButton(
        // 定義した再描画メソッドをボタン押下時のアクションにセット
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: new Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
```

1つのソースファイルで画面レイアウトからアクションまで記述できる
※画面右下のボタンをタップするたびに中央の数字がカウントアップされる
![017.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/e5fd0388-5002-11fb-8906-94329bed7a4f.png)