Flutter勉強記録3日目～公式ドキュメントのチュートリアル～

# はじめに
**本記事ですること、目的**

- [公式ドキュメントのチュートリアル]( https://flutter.dev/docs/get-started/codelab)をする
- 公式ドキュメントの翻訳ではない
- 諸事情により、いつもと別環境でチュートリアルを進め、スクショを撮り、いつもの環境に送信して記事を編集しているせいで、画質がかなり悪い部分がある。申し訳ないです……。
- 私自身、FlutterもDartも初心者のため、プログラム解説などは一切していない。今後できたらいいなと思っていますが、あまり期待はしないでほしい。

※本当は時間の都合上、公式ドキュメントのチュートリアルを進める予定はなかったが、色々とあって進める時間を手に入れたので進めることにした。色々に関しては、ここでは関係ないので割愛。

**注意**
もし、プログラムで分からないところ、問題があれば、[公式ドキュメント](https://flutter.dev/docs/get-started/codelab)の該当ステップの一番最後にある**Problems?**という部分から、その段階での手本を見ることができます。
本記事のステップ番号と、ドキュメントのステップ番号は対応しているので、そちらを参考にしてください。

# 0. 作るものの確認＆プロジェクトを作る
## 作るもの
第一段階では、[english_words](https://pub.dev/packages/english_words)というパッケージを用いて、二つのランダムな単語を組み合わせて表示する。
最終的には、二つのランダムな単語の組み合わせをリスト表示にし、スクロールするたびに新しい単語の組み合わせを生成→表示という無限にスクロールできるアプリを作る。
最終イメージはこんな感じ。
![_20210817_003143[1].JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528682/85de1c30-3b5f-1f8c-b93f-f2b00e392609.jpeg)

## プロジェクトを作る
作り方に関しては、以前の投稿を参照。
→[試しに一個プロジェクトを作る](https://qiita.com/ikeguma_Na/items/274223827b49f304b228#%E8%A9%A6%E3%81%97%E3%81%AB%E4%B8%80%E5%80%8B%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%82%92%E4%BD%9C%E3%82%8B)

# 1. `lib/main.dart`を書き換える
`lib/main.dart`の中身をすべて消し、以下をコピペする。

```Dart
// Copyright 2018 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Welcome to Flutter'),
        ),
        body: const Center(
          child: Text('Hello World'),
        ),
      ),
    );
  }
}
```

## 実行する
コードを走らせると**Hello, world**が出てくることを確認する。

## 公式ドキュメントに書かれていたコードの解説を一部抜粋
### main関数のところにある**=>**について
これは、関数やメソッドの中身が一行の場合に使えるものらしい。

```Dart
void main(){
runApp(MyApp());
}
```
と意味的には一緒だと思う。ただ、**=>**を使えば見た目がスッキリする。

これ以外にも色々と解説が書かれていたけど、よく意味が分からなかったので省略。気になる方は[Step 1: Create the starter Flutter app](https://flutter.dev/docs/get-started/codelab#step-1-create-the-starter-flutter-app)の最後、**Observations**欄を見てほしい。

# 2. パッケージを入れる
[english_words]( https://pub.dev/packages/english_words)というオープンソースのパッケージを使う。ちなみに、オープンソースのパッケージは[pub.dev]( https://pub.dev/)に色々とあるらしい。

[「Flutter勉強記録2日目～カメラを使って景色を見るだけのアプリを作ってみる～」]( https://qiita.com/ikeguma_Na/items/7f4543bb4d5159fd2c28)でもcameraパッケージを使ったが、今回はその方法と違う方法で、パッケージを入れる。多分どちらでもいいんじゃないかな？

## ` pubspec.yaml `を開き、`english_words: ^4.0.0`を追加する。
![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528682/24aaa7e8-e19f-c046-7d4a-85d6aa946a0d.png)
[ターミナル] > [新しいターミナル]からターミナルを開き、`flutter pub get`を入力
下みたいな結果が出てきて、パッケージを入れ終わる。
`Running "flutter pub get" in tutorial...                           612ms`

## `lib/main.dart`に行き、今入れたパッケージをインポートする。
` import 'package:english_words/english_words.dart'; `を既にあるimport文の近くに書く。
![画像2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528682/aea45e7b-35ae-5ec1-9ab4-af85a859cc30.png)

下に出てくる青色の波線は「そのパッケージ使われてないから、消した方がよくね？？」という忠告なので無視してOK。
VSCodeだと使われていないものは青色の波線、Android Studioだと灰色の文字になるらしい。

## `lib/main.dart`を以下に変更する
```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) {
    final wordPair = WordPair.random();
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Welcome to Flutter'),
        ),
        body: Center(
          child: Text(wordPair.asPascalCase),
        ),
      ),
    );
  }
}
```

変更部分は以下の通り（[公式ドキュメントのスクショ]( https://flutter.dev/docs/get-started/codelab#step-2-use-an-external-package)）
![画像3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528682/a6c2a45d-9221-2c78-d6c3-4107c2f84c46.png)

 

## 実行する
真ん中に適当な言葉が生成される。生成される言葉はランダムなので、違っていても気にしなくて大丈夫。
![画像4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528682/e56d0bbb-2ff7-2e5c-1fe8-8a441fa19d94.png)

# 3. 可変ウィジェット（Stateful Widget）の追加
ここ辺りのコードの意味は、よくわからなかった。
世の中には不変ウィジェット（Stateless widgets）と可変ウィジェット（Stateful Widget）があり、
- 不変ウィジェット → 中身を変えられない
- 可変ウィジェット → 中身を変えられる
らしい。不変とか可変とかは、私が適当に翻訳したので、言葉として使われているのか不明。

## 可変ウィジェットを追加する
`lib/main.dart`の一番最後にカーソルを合わせ、`stful`と入力する。すると、選択肢に`Flutter stateful widget`と出てくるので、これを選択する。
![画像5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528682/f501f7d2-4080-ceaf-14e5-3acf24c219a6.png)

## `RandomWords`と入力する
二つくらいクラスが追加され、カーソルが増殖するので、その状態で`RandomWords`と入力する。
![画像6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528682/04e08cee-d534-6554-8f42-2fe02af3fda9.png)

## `_RandomWordsState`の方を以下のように変更する（アンダーバーついている方）
```Dart
class _RandomWordsState extends State<RandomWords> {
    @override
    Widget build(BuildContext context) {
      final wordPair = WordPair.random();
      return Text(wordPair.asPascalCase);
    }
  }
```

## MyAppの方を以下のように変更する

```Dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Welcome to Flutter'),
        ),
        body: Center(
          child: RandomWords(),
        ),
      ),
    );
  }
}
```

ビフォーアフターは以下の通り（これも[公式ドキュメントのスクショ](https://flutter.dev/docs/get-started/codelab#step-3-add-a-stateful-widget)）
![画像7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528682/bcc1bacb-3479-8928-a047-6e2411aa591a.png)

## 実行する
先ほどまでと変わらず、ただランダムな単語が表示されるだけのアプリになる

# 4. ランダムな単語が並ぶリストを作る
ここでは、ユーザがスクロールすると無限に単語を生成するリストを作る。
以下のコードの意味は、私自身もよく分かっていないです。Dart特有？の書き方のせいもあり、公式ドキュメントだけでは、何となくしか意味を理解できませんでした。

記事冒頭でも書いた通り、時間があれば解説記事を探すか、意味を一つずつ調べて解説する記事を作ろうかなと思いますが、あまり期待しないでほしいです。もし、解説している記事をご存知の方がいらっしゃればコメントで教えていただければ助かります。

## `_RandomWordsState`に`_suggestions `と`_biggerFont `を追加する
最初二行が追加部分。あとは変更していない。

```Dart
  class _RandomWordsState extends State<RandomWords> {
    final _suggestions = <WordPair>[];  //追加部分
    final _biggerFont = const TextStyle(fontSize: 18.0); //追加部分
    @override
    Widget build(BuildContext context) {
      final wordPair = WordPair.random();
      return Text(wordPair.asPascalCase);
    }
  }
```
## `_buildSuggestions()`関数を`_RandomWordsState`クラスに追加
`_buildSuggestions()`関数を。先程追加した2行の後ろに追加する。
`_buildSuggestions()`関数以降の部分は変更が無いので省略している。

```Dart
  class _RandomWordsState extends State<RandomWords> {
    final _suggestions = <WordPair>[];
    final _biggerFont = const TextStyle(fontSize: 18.0);
    //ここ以降追加部分
    Widget _buildSuggestions() {
    return ListView.builder(
        padding: const EdgeInsets.all(16.0),
        itemBuilder: /*1*/ (context, i) {
          if (i.isOdd) return const Divider(); /*2*/

          final index = i ~/ 2; /*3*/
          if (index >= _suggestions.length) {
            _suggestions.addAll(generateWordPairs().take(10)); /*4*/
          }
          return _buildRow(_suggestions[index]);
        });
  }
//追加部分ここまで

//以降省略
```

## `_RandomWordsState`に`_buildRow()`関数を追加する
`_buildRow()`関数を先程追加した部分の直後に追加する。

```Dart
class _RandomWordsState extends State<RandomWords> {
    final _suggestions = <WordPair>[];
    final _biggerFont = const TextStyle(fontSize: 18.0);

  Widget _buildSuggestions() {
    //省略
  }

//ここから追加部分
  Widget _buildRow(WordPair pair) {
    return ListTile(
      title: Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
    );
  }
//追加部分ここまで

//以降省略
```

## `_buildSuggestions()`を使うために、`_RandomWordsState`クラスの`build()`メソッドを改良する
`_RandomWordsState`クラスの最後辺りにある`build()`を以下のように変更する。

```Dart
@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text('Startup Name Generator'),
    ),
    body: _buildSuggestions(),
  );
}
```

## `MyApp`クラスの`build()`を以下のように変更する

```Dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Startup Name Generator',            
      home: RandomWords(),
    );
  }
}
```

ビフォーアフターは以下の通り（例によって[公式ドキュメントのスクショ](https://flutter.dev/docs/get-started/codelab#step-4-create-an-infinite-scrolling-listview)）
![キャプチャ.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528682/c72b51f7-44e7-0226-5502-511935028c80.jpeg)

## 実行する
実行すると、無限にスクロールできる意味不明な組み合わせの英単語リストが出てくる
![_20210817_003143[1].JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/528682/85de1c30-3b5f-1f8c-b93f-f2b00e392609.jpeg)

# 三日目終わり
やっぱりDartの文法が分からないと辛い。コードの意味が分からない。
未だにウィジェットとかの概念を理解できていない。

ここまでは、どちらかというと目的のものを作るために無理矢理突っ走ってきた感じですが、ここらで少しコード復習タイムを取った方が良い気がする。

そのため、次からはコードの解説記事とかになるかもしれないし、何となくは分かったけど解説できるほど理解できなくて、解説記事は上がらないかもしれない。