Flutter入門[3]: 本当に基本的なアプリから作ってってみる

今回はFlutterで本当に基本的なアプリから作っていきます。
細かいところを見つつ固定長のリストを表示するだけのアプリを作成していきます。

以下の点について参考になる記事を目指します。
※VScodeを使用していくので、全てVScodeを利用する際の手順になります。多分、他のIDEでも似たようなもんだと思ってます。

- 基本的なアプリの作成方法
- ホットリロードの使い方
- なんとなくFlutterのウィジェットを理解
- ListViewの作り方

最終的には[ココ](https://flutter.dev/docs/get-started/codelab)あるような感じのずっとスクロールできるアプリにもっていきます。写経してみて感覚的にはわかったんですが、細かいところを見ていきたいと思ったので、ちょっとだけ別ルートから辿り着こうと思います。完成は次回の記事になると思われます。

上のページを写経して出来上がるのは以下のような、スクロールしていくと無限に英単語がランダム表示されるようなアプリです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/468c1e95-ca55-4ebe-7f39-2c919a0b59e5.png)

アプリを作成する記事としては最初になるので、VScodeで作成する手順をなるべく細かく書いていきます。

## 1.プロジェクトの作成
まずは、Flutterプロジェクトを作ります。
VScodeのコマンドパレット(View > Command Palette...)でFlutter: New Projectを選択して新しいプロジェクトを作成します。プロジェクト名はなんでもいいんですが、とりあえず"plain_app"にしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/0fabd342-0b54-abdc-8077-88ad5fc511a1.png)

## 2.接続デバイスの選択
デバイス接続できている場合にはここは飛ばして大丈夫です。
VScodeのステータスバー(一番下にあるやつ)の右端に"No Device"と表示されてたらデバイスが接続されていない状態です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/28091d45-6e42-4543-6719-c2887b10d834.png)
この時には"No Device"の部分をクリックすると上の方にコマンドパレットが開くのでそこからシミュレータを選ぶなら、持ってる端末を接続するなりして下さい。
もし、コマンドパレットに何も表示されないようならFlutterのデバイス設定ができてない気がします。[前の記事](https://qiita.com/ShZgZ_Shogo/items/ffe4c839023e3e7a2883)が参考になるかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/223569eb-791b-a7cd-b21c-4b97d26e1ba2.png)

先程まで"No Device"となっていた箇所に選択したデバイス名が表示されていれば接続成功です。

## 3.起動
まずは、作成されたテンプレ状態がどのようなものか確認します。
VScodeのアクティビティバー(一番左側にある縦長のバー)から実行アイコン(虫と三角のやつ)を選択し、"Run and Debug"ボタンから実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/7ede0c22-e188-20e2-7a9e-bd2cfe665706.png)

最初に起動する際はちょっとだけ時間が掛かりますが、以下のような画面が表示されるはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/872cac1c-172d-b416-d229-14d55d3b87ef.png)
右下にあるプラスボタンを押すと画面中央のカウントが増えていきます。

一先ず、これでFlutterアプリが正常に起動することの確認が取れました。

## 4.何も無いアプリに変更
lib/main.dartの内容を全て削除して以下のコードにして下さい。

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

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

class MyApp extends StatelessWidget { // (2)
  @override
  Widget build(BuildContext context) {
    return MaterialApp( // (3)
      home: Scaffold( // (4)
      ),
    );
  }
}
```

多分保存すればホットリロードして画面が以下のように何も表示されていない白い画面になっているはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/56f42104-edda-1558-fe85-5d95a9697083.png)
ホットリロードは画面上部に表示されている雷マークからも行うことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/2649b91e-fa15-26f0-2a14-98d6b0209681.png)

軽くコードについて解説します。
Flutterにおいてはアライメントやパディング、レイアウトを含むほぼ全てのものがウィジェットで表現されるそうです。このことを念頭において見ていきます。

(1)これはdartのワンライナー記法で、普通に記述すると以下のようになります。

```dart
void main() {
  runApp(MyApp());
}
```
(2)MyAppは抽象クラスStatelessWidgetを実装しています。
runAppは以下のような定義で、これ自体ウィジェットを受け取り、それをインフレートし画面に表示するメソッドです。

```dart
void runApp(Widget app)
```
上のことからもわかるようにMyAppもまたウィジェットなわけです。
※上の説明でインフレートっていう言い方をしましたが、Androidにもinflateってあるけどどういう意味かわかったなかったんですが、息を吹き入れて膨らませる的な意味があるらしいです。なので、ウィジェットを展開し画面に表示できる形にするみたいな意味かと思います。もしちゃんとわかる人いたら是非教えて下さい。

(3)buildの返却型がWidgetであることからもわかりますが、MaterialAppは抽象クラスStatefulWidgetを実装しているウィジェットです。MaterialAppは[マテリアルデザイン](https://material.io/design)を使ったアプリを作成するために使われるそうです。
(4)Scaffoldもまた抽象クラスStatefulWidgetを実装しているウィジェットです。

今のところ、MaterialApp配下は以下のようなウィジェットツリーになっています。
いきなりウィジェットツリーって何って思われるかもしれませんが、公式チュートリアルでもいきなり出てきたんですが、ウィジェットをどんどん詰め込んでいき木構造を作ることからそういう言い方をしているんだと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/508cc9fa-7b45-1c88-5e36-4f77a1e98683.png)

## 4.画面にウィジェットを追加
以下のようにScaffoldのコンストラクタの引数bodyにウィジェットを渡すことで画面に要素を追加することができます。コードを追加し、保存します。

```dart
            ...
      home: Scaffold(
        body: Text('Hello, World!!!!'),
      ),
            ...
```
以下のように表示されます。ちょっと見辛いですが、左上に表示されてます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/a3b07dd2-11eb-0e18-a35c-1b15c9635de4.png)


## 5.アプリケーションバーの追加
ScaffoldのコンストラクタにappBarを渡すことでアプリケーションバーを作成することができます。

```dart
            ...
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter')
        ),
        body: Text('Hello, World!!!!'),
      ),
            ...
```
以下のようにアプリケーションバーが作成されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/eb8bade7-cc9b-8eea-003d-df9d5980805b.png)
Text内の文字列を変更し、保存すればホットリロードで画面に変更が反映されます。
ホットリロードの反映が本当に早くて今のところ全然ストレス無いです。

今のウィジェットツリーはこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/7bdc4dd3-505e-1cc8-19fb-1bf3ac9751b8.png)

## 6.中央寄せ
上でも説明しましたがFlutterではアライメントもウィジェットになります。
Centerウィジェットを作成し、Text('Hello, World!!!!')を内部に移動させます。

```dart
            ...
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter')
        ),
        body: Center(
          child: Text('Hello, World!!!!'),
        ),
      ),
            ...
```
これによって上下左右の中央寄せされて表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/494df2bf-96a5-1174-2393-9182b9068454.png)

## 7.リストの表示
リスト表示のためにはListViewを利用します。ListViewの引数childrenにウィジェットのリストを渡します。
buildメソッド配下を以下のように変更して下さい。

```dart
            ...
    final _biggerFont = TextStyle(fontSize: 30.0);
  
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter')
        ),
        body: ListView(
          children: <Widget>[
            Text('A', style: _biggerFont),
            Divider(),
            Text('B'),
            Text('C', style: _biggerFont),
          ],
        ),
            ...
```
TextStyleクラスを利用してテキストのスタイルを定義しています。これをTextクラスの引数styleに渡すことでそのテキストウィジェットにスタイルを適用することができます。また、Dividerクラスは水平の線を表すウィジェットです。AとBの間にのみ水平線が入っていることが確認できるかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/0eb40dee-b387-ee84-0d5a-d9651813556c.png)

ここまででこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/656102/751edda2-948a-8f29-a882-c95ce6779c01.png)

# まとめ
ウィジェットツリーを実際に描いて見ましたが、ここまでシンプルにも関わらず結構複雑になりました。
部品の分け方ちゃんとしないとすぐに膨大なウィジェットツリーが出来あがっちゃいそうな気がしますね。

只今、リモートで受けられる案件を探してますので、何かあったら是非お願いします。