Flutterにおけるクラスの役割


##はじめに
この記事はFlutterを勉強している時の様子をそのまま書き下ろしたものです。飛躍のない説明には自信がありますが,話し言葉等あったり,雑な表現が多いです。間違っているところ等あればコメント下さい。
## Stateless(静的)なアプリをStatefulWidget継承クラスで再現
静的(Stateless)な機能のみを持ったアプリ(つまり**見た目**だけ)の場合,**StatelessWidget**を継承したクラスのみで作成することができる。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549093/7f0fd941-5838-300e-3d55-30619198fe92.jpeg" alt="スクリーンショット 2020-09-27 18.03.38.jpg" width = "250">


```Dart
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("スイッチ"),
        ),
        body: Center(
          child: Text("アイウエオ"),
        ),
      ),
    );
  }
}
```

しかし,これではユーザの入力を検出するといった動的(Stateful)な機能を果たすことができない。

そこで**StatefulWidget**を継承したクラスを持ちいる。

例として,全く同じ機能のアプリをわざわざStatefulWidgetを用いて再現する。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549093/7f0fd941-5838-300e-3d55-30619198fe92.jpeg" alt="スクリーンショット 2020-09-27 18.03.38.jpg" width = "250">


```Dart
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("スイッチ"),
        ),
        body: Center(
          child: ChangeForm(),
        ),
      ),
    );
  }
}

class ChangeForm extends StatefulWidget{
  _ChangeFormState createState() => _ChangeFormState();
}

class _ChangeFormState extends State<ChangeForm> {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      child: Text("アイウエオ"),
    );
  }
}
```



二つの違いは前者の場合StatelessWidgetを継承したMyAppクラスの中でTextウィジェットを用いているのに対し,後者はStateクラスでTextウィジェットを作っている。

```Dart
return Container(
      child: Text("アイウエオ"),
    );
```

ここ。**StatefulWidgetでは**Containerが返り値となっている。そしてState継承クラスとStatefulWidgetクラスはつながっている。ここまでは良さそうだ。

あとはStateを継承したChangeFormクラスの存在であるが,これは呪文として頭においておくぐらいでいいと思われる。`StateulWidget継承クラス名 createState() =>StateulWidget継承クラス名()  `というテンプレが決まっていそうだ。

```Dart
class ChangeForm extends StatefulWidget{
  _ChangeFormState createState() => _ChangeFormState();
}
```



## ボタンを押して値が変わるStateful(動的)なアプリを作る

嘘。まだステップを踏む。

先ほどの内容の**StatefulWidget**を継承した_ChangeFormStateクラスの中では文字を定義するとき,

`Text("アイウエオ")`

と行っていた。これを変数を用いて表現すると

```Dart
class _ChangeFormState extends State<ChangeForm> {
  String message = "アイウエオ";
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      child: Text(message),
    );
  }
}
```

このようになる。

先ほどとの違いは

`String message = "アイウエオ";`の存在だ。

messageは”アイウエオ"なので,Text()の中にそのまま入れることができる。

##### いよいよタイトル通りボタンを押して値が変わるようにしていく。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549093/1ae51f39-3d83-d97f-997e-cb92c0a9933c.jpeg" alt="スクリーンショット 2020-09-27 18.05.48.jpg" width = "400">

さっき変数を定義するところまでは行ったので、もう一つ**StatefulWidget**の要となる値を変える関数を定義する。変数を行うためにはその関数の中に`setState()`を書く必要があることに留意したい。

先ほどの`String message = "アイウエオ"`の下に,関数を定義する。

```
void buttonPressed() {
  setState(() {
    title = "ボタンが押された";
  });
}
```

これがtitleを変化する関数だ。きちんと`setState()`の中にtitleを変える命令が書かれている。

これがボタンを押されたときに実行されるようにすればいい。

ボタンのウィジットの引数`onPressed`はボタンが押されたときの動きを制御する。なので,さっき作った`buttonPressed()`を書けばいい。

```
FlatButton(
  onPressed: buttonPressed,
  child: Text("ボタン"),
)
```

FlatButtonに文字を入れるには,子要素にTextを入れれば良い。

クラス全体のソースを見て流れを確認。

```Dart
class _ChangeFormState extends State<ChangeForm> {

  String title = "ボタンを押してくれ";

  void buttonPressed() {
    setState(() {
      title = "ボタンが押された";
    });
  }
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      child: Column(
        children: <Widget>[
          Text(title),
          FlatButton(
            onPressed: buttonPressed,
            child: Text("ボタン"),
          )
        ],
      ),
    );
  }
}
```

ウィジット を複数用いているので,ウィジット を鉛直方向に並べる**Column**を使っている。

最後に全体のソースを見て確認。

```Dart
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("スイッチ"),
        ),
        body: Center(
          child: ChangeForm(),
        ),
),
);
}
}

class ChangeForm extends StatefulWidget{
  _ChangeFormState createState() => _ChangeFormState();
}

class _ChangeFormState extends State<ChangeForm> {

  String title = "ボタンを押してくれ";

  void buttonPressed() {
    setState(() {
      title = "ボタンが押された";
    });
  }
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Container(
      child: Column(
        children: <Widget>[
          Text(title),
          FlatButton(
            onPressed: buttonPressed,
            child: Text("ボタン"),
          )
        ],
      ),
    );
  }
}
```