必要に迫られたのでFlutterを学びます②～Hello World編～

[環境構築編](https://qiita.com/Takahiro-Hirai/items/4fee6ad3e807254cae3c)　
[Hello World編](https://qiita.com/Takahiro-Hirai/items/67f501ee8ed51982f5dc) ⇐ 今ここ
[外部パッケージ利用編](https://qiita.com/Takahiro-Hirai/items/9c5ede0d83951cd6c1b8)
[StatefulWidget利用編](https://qiita.com/Takahiro-Hirai/items/f9b0a4d4a9011eab92dc)



ニュイ・ソシエール氏のウイポ実況動画で一押しの部分は名前大喜利です。
さて先の記事で環境構築は行ったので、実際に勉強してみます。
Hello Worldしようとして嵌まることってありますよね。。。

## 第二章 betaチャンネルに切り替える
2020年5月現在でベータ版のようですが、FlutterをWebでも動作可能なように切り替えます。

チャンネルをベータ版に変更
※ログを見る限り、gitのインストールは必要なのかもしれません。。。

```
>flutter channel beta
Switching to flutter channel 'beta'...
git: From https://github.com/flutter/flutter
git:  * [new branch]          Hixie-patch-1       -> origin/Hixie-patch-1
git:  + e6b34c2b5...2738a1148 beta                -> origin/beta  (forced update)
git:  * [new branch]          dart_development_service -> origin/dart_development_service
git:    c2b7342ca..2738a1148  flutter-1.18-candidate.11 -> origin/flutter-1.18-candidate.11
git:    610dc170d..9d58a8706  master              -> origin/master
git:  * [new branch]          timsneath-uikitview -> origin/timsneath-uikitview
git:  * [new tag]             1.18.0-11.1.pre     -> 1.18.0-11.1.pre
git: Branch 'beta' set up to track remote branch 'beta' from 'origin'.
git: Switched to a new branch 'beta'
Successfully switched to flutter channel 'beta'.
To ensure that you're on the latest build from this channel, run 'flutter upgrade'
```
促されるままにUpgradeします。

```
>flutter upgrade
Checking Dart SDK version...
Downloading Dart SDK from Flutter engine ef9215ceb2884ddf520d321bcd822d1461330876...
Unzipping Dart SDK...
Building flutter tool...
Running pub upgrade...
Flutter is already up to date on channel beta
Flutter 1.18.0-11.1.pre • channel beta • https://github.com/flutter/flutter.git
Framework • revision 2738a1148b (10 days ago) • 2020-05-13 15:24:36 -0700
Engine • revision ef9215ceb2
Tools • Dart 2.9.0 (build 2.9.0-8.2.beta)
```
初回なのでWebサポートを有効にしておきます。

```
>flutter config --enable-web
Setting "enable-web" value to "true".

You may need to restart any open editors for them to read new settings.
```
Editorなどは再起動が必要そうなので実行しておきます。

### Flutterのチャンネルについて
Flutterは4種類のチャンネルがあります。
詳しくは私も分かりませんが、とりあえず利用できる機能がチャンネルによって差があるみたいなので、
パッケージ群みたいな認識で私の認識は止まりました。

```
>flutter channel
Downloading package sky_engine...                                   0.4s
Downloading flutter_patched_sdk tools...                            1.1s
Downloading flutter_patched_sdk_product tools...                    1.4s
Downloading windows-x64 tools...                                    2.8s
Downloading windows-x64/font-subset tools...                        0.4s
Flutter channels:
  master
  dev
* beta
  stable
```
デフォルトはstableで安定版。
基本的に開発とかはこのチャンネルで行うことになるのだと思います。
今回はあくまでキャッチアップなのでstableかどうかはこだわっていません。

betaはFlutter for Web対応版という立ち位置でしょうか。
Flutter自体はiOSとAndroidの双方に対応できるという状態ですが、チャンネルをbetaにすると、
Webにまで拡張できるよ。ということみたいです。
2019年12月に発表されたばかりみたいなので、もう少し様子見したほうが無難かもしれません。

Devは先行的に最新バージョンを利用できるチャンネルみたいです。
2020年5月現在では1.19.0-1.0.preバージョンが利用できるみたいです。

Masterチャンネルは何なんでしょう？
[公式サイト](https://flutter.dev/docs/development/tools/sdk/releases)見る限り、通常利用できなさそうだし、GitのMasterブランチみたいなものですかね？

## 第三章 Hello Worldする
とりあえず最初なのでHello Worldしましょう。
余談ですが、Google翻訳を使うと「Hello World」が「こんにちは、世界」に訳されるので苛々しますよね？

### とりあえずデフォルトプロジェクトを起動させてみる
このあたりの導入部分は公式が手厚くサポートしてくれてます。
他のドキュメントもそうですが、Flutterのドキュメントは読みやすい気がします。
〇racleにもぜひ見習ってほしい。。。

VSCodeの環境を準備したので、以下はVSCodeで続けていきます。
F1キーから「Flutte new project」を選択し、プロジェクト名を入力します。
すると
![2020-05-24_01h46_19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318745/418fd5f1-6a55-9936-e98f-c9ca10d0185f.png)
こんな感じでmain.dartが出来上がります。

この状態でF5キーを押下するとデバッグモードが起動します。
デバッグモードのローンチには少し時間がかかります。
とりあえずChromeで表示させてみるとこんな感じ
![2020-05-24_02h47_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318745/86b98fdf-5fc0-fa50-0281-2e64d2adfd39.png)

Nexus(Android)だとこんな感じです
![2020-05-24_02h56_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318745/1d4735a1-eec7-b79a-2d7b-4df77d66d0ca.png)
きれいに見えますね。

今後のデバッグ等はこのエミュレータを用いていきます。

### ついにHello Worldする
とりあえずコードを書いてみます。
コード自体は[Codelabs](https://codelabs.developers.google.com/codelabs/first-flutter-app-pt1/#2)が教えてくれました。

```main.dart
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: const Text('Hello World'),
        ),
      ),
    );
  }
}
```
エミュレータでは下記の通り表示されます。
![2020-05-24_03h31_48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318745/7fe5f454-3419-1b9a-dbe7-ec4ddc555158.png)

これだけだとなぜそう動くの推測の域を出ないので、もう少しコードについて調べます。

### runApp(Widget app)
ドキュメントは[こちら](https://api.flutter.dev/flutter/widgets/runApp.html)
見るからにメイン関数を実行するようなメソッドですね。
とりあえず引数にはWidgetなるものを渡しておけば良さそう。。。
という認識で次に進みます。

### StatelessWidget
良くわからないのをextendしているので調べましょう。

そもそもWidgetって何って話です(私はreactには詳しくなくて。。。)。
公式のドキュメント類は読みましたが、ちょっとつながりが良く分からんぞということで下記サイトにお世話になりました。

[FlutterにおけるWidgetとElementとRenderObjectの基本](https://engineer.recruit-lifestyle.co.jp/techblog/2019-12-24-flutter-rendering/)

すごく関係性を分かりやすくまとめてくださっているので、ここでの説明は割愛します。
なおこのあたりの公式ドキュメントは下記になります。

[Widget](https://api.flutter.dev/flutter/widgets/Widget-class.html)
[Element](https://api.flutter.dev/flutter/widgets/Element-class.html)
[RenderObject](https://api.flutter.dev/flutter/rendering/RenderObject-class.html)

さて上記を踏まえてStatelessWidgetですが
[公式ドキュメント](https://api.flutter.dev/flutter/widgets/StatelessWidget-class.html)によれば、

> Stateless widget are useful when the part of the user interface you are describing does not depend on anything other than the configuration information in the object itself and the BuildContext in which the widget is inflated.

とあるので、静的なページの表示に向いているのでしょう。
逆に動的なページの場合はStatefulWidgetを使うのが良いみたいです。
このあたりの使い分けは後々覚えていかないといけないですね。

でStatelessWidgetは戻り値Widgetのbuild(BuildContext context)メソッドを持ちます。

### build(BuildContext context)
ドキュメントは[こちら](https://api.flutter.dev/flutter/widgets/StatelessWidget/build.html)。

> Describes the part of the user interface represented by this widget.

とあるので、WidgetのUIの部分を構築するメソッドみたいです。
実際のコードでも中のreturnで、titleとか要素を返していることから見て、ここの認識は間違いなさそう。

### [MaterialApp](https://api.flutter.dev/flutter/material/MaterialApp-class.html)

> A convenience widget that wraps a number of widgets that are commonly required for material design applications. It builds upon a WidgetsApp by adding material-design specific functionality, such as AnimatedTheme and GridPaper.

複数のUIの要素をまとめたデザイン用Widgetといったところでしょうか。
コンストラクタはこんな感じ

```
MaterialApp({Key key, GlobalKey<NavigatorState> navigatorKey, Widget home, Map<String, WidgetBuilder> routes: const {}, String initialRoute, RouteFactory onGenerateRoute, InitialRouteListFactory onGenerateInitialRoutes, RouteFactory onUnknownRoute, List<NavigatorObserver> navigatorObservers: const [], TransitionBuilder builder, String title: '', GenerateAppTitle onGenerateTitle, Color color, ThemeData theme, ThemeData darkTheme, ThemeMode themeMode: ThemeMode.system, Locale locale, Iterable<LocalizationsDelegate> localizationsDelegates, LocaleListResolutionCallback localeListResolutionCallback, LocaleResolutionCallback localeResolutionCallback, Iterable<Locale> supportedLocales: const [Locale('en', 'US')], bool debugShowMaterialGrid: false, bool showPerformanceOverlay: false, bool checkerboardRasterCacheImages: false, bool checkerboardOffscreenLayers: false, bool showSemanticsDebugger: false, bool debugShowCheckedModeBanner: true, Map<LogicalKeySet, Intent> shortcuts, Map<LocalKey, ActionFactory> actions})
```
長い。。。
ここではサンプルに使用した部分と公式ドキュメントで触れられている部分だけ纏めます。

#### [title](https://api.flutter.dev/flutter/material/MaterialApp/title.html)
名前の通り、タイトルです。
型はString型。
画面に表示されるタイトルではなく、アプリケーションのタイトルに該当する模様。
iOSではこの値を利用できないので注意。

ちなみに最初、スマホ画面に表示されるタイトル(htmlでいうh1)だと思って、私は下記のようなコードを書いて怒られました。

```main.dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Hoge Hoge'
  }
}
```
![2020-05-24_04h55_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318745/45ed1a1b-e3ce-4222-f846-33a1ef224997.png)
すごくエラーって感じがする(小並感)


#### [home](https://api.flutter.dev/flutter/material/MaterialApp/home.html)
型はWidget型。
initalRouteが明示的に存在しない場合、アプリケーションが正常に動作したときに最初に表示されるページのようです。
WordPressでいうindex.htmlとかそういうのに該当するような気がする。

#### [Scaffold](https://api.flutter.dev/flutter/material/Scaffold-class.html)
マテリアルデザインの基本的なレイアウト構造を規定するクラスです。
ここで表示されるテキストや色などを決めているみたいですね。
いくつかサンプルを載せてみます。

背景色を追加

```main.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: const Center(
          child: const Text('Hello World'),
        ),
        backgroundColor: Colors.blueGrey.shade200,
      ),
    );
  }
}
```
![2020-05-24_05h08_25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318745/74b9c77f-b987-8200-78ba-9a7a2dbde1cc.png)

ボタンを追加してみたり

```main.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: const Center(
          child: const Text('Hello World'),
        ),
        backgroundColor: Colors.blueGrey.shade200,
        floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        ),
      ),
    );
  }
}
```
![2020-05-24_05h12_55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318745/59cc16e3-7369-8a31-b339-60e4d8dd4aba.png)

中央部分に表示される文言を変えてみたり

```main.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: const Center(
          child: const Text(' I am a Bar.'),
        ),
        backgroundColor: Colors.blueGrey.shade200,
        floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        ),
      ),
    );
  }
}
```
![2020-05-24_05h15_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318745/cd0e655d-5e6d-739d-9312-2555df1129c3.png)


以上、とりあえずHello Worldまで
大まかな理解はできました。
簡単なページならScaffoldで対応できるということですかね。。。