そうだ　Flutter、やろう。

Advent Calendar 2019、2回目の登場です。
予定していた記事のネタは、いざ書いてみるとどうにもパッとせず、土曜日からずっと胃の痛い週末を過ごしています。（12/1 13:00に書いています）

昼食中に、妻がXamarinでスマホアプリを作ることになりそう、という話をしていました。
「Xamarin？他にもなんかあったような、、、React Nativeとか、Flutterってやつとか、聞いたことあるなあ」と、突然、Flutterという単語を思い出しました。
予定していたテーマに行き詰まりを感じていた私は、書きかけの記事を捨てて、Flutterに挑戦してみることにしました。
サーバーサイドエンジニアリング一筋の私は、ネイティブアプリの経験は全くありません。かつて何度か挑戦しようと思いましたがXcodeのinstall待ってる間に眠気に襲われてそれっきりです。さて、今回はどうなるのでしょうか。。。

# まずは公式サイトを確認

今、私は、Flutterについて、「iOS/Androidアプリが1つのコードで作れる」「Dartという言語を使う」ということしか知りません。まずはQii...ではなく公式サイト[https://flutter.dev/](https://flutter.dev/)を見てみることにします。
[動画](https://www.youtube.com/watch?v=5VbAwhBBHsg&feature=youtu.be)では、Flutter始めるなら今が完璧なタイミングさ！という力強いメッセージ。じゃあやってみましょうか。
https://flutter.dev/docs/get-started/install

# Get Started

まずはSDKをダウンロードして適当なところでunzipしてpathを通して、と書いてあるので、そのとおりやっていきます。
homebrewでinstallできないかなと思ったのですが、見つからなかったので、公式サイトからflutter_macosv1.9.1+hotfix.6-stable.zipというファイルを落としてきました。
v1.9.1+hotfix.6-stableというあたりに"xx_final_修正確認済み_最新版.xlsx"みたいな風味を感じますが、気にせず続けます。

flutter doctorというコマンドを打て、とのことなので打ちます。
flutter開発に必要な環境が整っていない場合、そのように表示されるので、表示に従って色々install,updateしていきます。
私の場合はこんな感じでした。
<img width="1266" alt="スクリーンショット 2019-12-01 14.09.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56357/9636084b-2fd2-72ac-a9ac-11183bab5ff1.png">
言われるがまままにコマンド打ったりgem installを進めますが、Xcodeのアップデートに引っかかったので、おやつ休憩となりました。(12/1 14:30に書いています)
こんな調子で今日中に記事かけるのだろうか？

# Platform毎のセットアップ

[iOS/Android/Webのセットアップ手順が記載されています。](https://flutter.dev/docs/get-started/install/macos#platform-setup)どれか一つ完了していればFlutter開発始められるとのことなので、Xcodeは放置しておいて先に進みます。
WebについてはGoogle Chromeを入れるだけなのですが
> Flutter on the web is currently available as a technical preview.

ということでした。今回はネイティブアプリを作りたいので問題ないです。

# エディタのセットアップ

[VSCodeのセットアップ手順](https://flutter.dev/docs/get-started/editor?tab=vscode)が記載してあります。
Flutterのプラグインをinstallするだけなので、やっておきます。
VSCode以外にAndroid Studioの手順も記載してありますが、[こちら](https://flutter.dev/docs/get-started/editor?tab=androidstudio)も単にプラグインをinstallする手順となっています。手順細かいのは嬉しいですね。

ここまでやってる間にXcodeのアップデートが完了しました。flutter doctor打ったら、「規約に同意せよ」的なものとかが出ました。あれこれagreeして再度flutter doctorして、やっと

```
No issues found!
```
となりました。(12/1 15:30に書いています)

# Create the app

環境構築が終わり、"開発"らしきことをやっていきます。[ここ](https://flutter.dev/docs/get-started/test-drive?tab=vscode)もエディタ毎の手順が記載してあります。
VSCodeでは、コマンドパレットから"Flutter:New Project"を選択してアプリ名を入力する、という手順でした。
手順の通りに進めると以下の出力が得られたので、どうやらこの手順はプロジェクトのディレクトリ作成と以下コマンドを打ってくれるショートカットなのですね。

```
flutter create --ios-language swift --android-language kotlin .
```

[Terminal & editor](https://flutter.dev/docs/get-started/test-drive?tab=terminal)の手順でも"flutter create"コマンドを使っていますが、こちらはSwift, Kotlinというオプションがありません。createコマンドのヘルプを見る限り、デフォルトでSwift, Kotlinが指定されるようなので、現在時点では、つけてもつけなくても同じことのようです。

# Run the app

デバイスをDevice Selectorで選択してSetting buttonを押せ、[と書いてあります。](https://flutter.dev/docs/get-started/test-drive?tab=vscode)Setting buttonがどれなのかわからず、VSCodeの右下にあるベルのマークを押したところF5キーを押せ、と出たので押してみたところ、無事アプリが起動しました。
<img width="503" alt="スクリーンショット 2019-12-01 15.51.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56357/e69e6269-cdec-6edf-0a13-e4224fa7454b.png">
プラスを押すと、真ん中の数字が 0 -> 1 -> 2と変化していきます。

## hot reloadを試す

Flutterは、アプリの再起動不要、ステートを保持したままコードの再読み込みができるようになるhot reload機能が備わっているようです。
Get Startedの記載のとおり、
'You have pushed the button this many times'
の文言を
'You have clicked the button this many times'
に変更して、cmd + s でファイルを保存してみると、VSCodeのDebug Consoleに

```
Reloaded 1 of 468 libraries in 131ms.
```
と表示され、アプリは起動したままシミュレーター内の文言表示が変わっています。
<img width="472" alt="スクリーンショット 2019-12-01 15.59.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56357/18321657-e1a2-55df-2ed6-6bdcc572497b.png">


これは楽ですね。(12/1 16:30に書いています)

# アプリを作ってみよう　その1

[このページ](https://flutter.dev/docs/get-started/codelab)では、「スタートアップ企業の社名候補を表示するアプリ」を作っていきます。
VSCodeのコマンドパレットから"Flutter:New Project"を選んで、"startup_namer"というアプリ名を入力します。

今回はiOSシミュレーターではなくNexus5Xの実機をつかっていきます。

まずは[言われたとおりにコピペしてHello World](https://flutter.dev/docs/get-started/codelab#step-1-create-the-starter-flutter-app)していきます。
![IMG_20191201_164649.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56357/e5f4eec6-3a40-f56b-e2b8-29554158c9fc.jpeg)
先程と同じアプリが、今度は実機のNexus5Xで起動しています。奥のふかふかしたものは猫です。
[Material Design](https://material.io/design/)についての言及があり、普段触れないデザインの世界の話が面白く、読みふけってしまいました。随分日が暮れてきました。(12/1 17:00に書いています)

続いて、[english_wordsというDartのパッケージ](https://pub.dev/packages/english_words)を使っていきます。
プロジェクトフォルダ直下にあるpubspec.yamlというファイルのdependenciesの項目に、以下追記し、ファイルをsaveします。

```
english_words: ^3.1.0
```
ファイルをsaveした瞬間、勝手に"flutter pub get"が発行されました。english_wordsのパッケージをgetしたようです。Railsで言えばGemfile修正してsaveしたらbundle installしてくれるみたいな感じ。VSCodeに入れたパッケージはこういうこともしてくれるのですね。まるでIDEですね。


その後、english_wordsをimportして、ちょちょいと書き換えるとHelloWorldではない文言が表示されるようになりました。
![IMG_20191201_171821.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56357/4293ac1d-037b-9f04-6499-cd6f46aaa4c9.jpeg)

将来立ち上げる会社の社名が決まってしまいました。

## Statefulにしていく

ここまではimmutableな、statelessなwidgetを扱っていましたが、[ここからはstatefulなwidgetを使っていきます。](https://flutter.dev/docs/get-started/codelab#step-3-add-a-stateful-widget)
widget、という概念が何なのかわからないままwidgetと書きました。気持ち悪いので[ここ](https://flutter.dev/docs/development/ui/widgets-intro)を読みました。ざっくり、UIを構成する要素、という理解をしました。
![IMG_20191201_174637.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56357/bcb174e8-8dbc-e73d-6ecb-b7fed8530307.jpeg)

アプリの見た目は変わっていませんが、テキスト部分がstatefulなwidgetに変わっており、RandomWordsStateが生成する文字列を表示するように変わっています。熊はwildからstrictに変わりました。

## 無限スクロールリストを表示する

続いて[無限スクロールリストを作っていきます](https://flutter.dev/docs/get-started/codelab#step-4-create-an-infinite-scrolling-listview)。
[ListView](https://api.flutter.dev/flutter/widgets/ListView-class.html)というclassを使って、リスト表示を作っていきます。
ListViewはitemCountを渡せばスクロールの範囲を限定できるのですね。
水平線引っ張るための[Divider](https://api.flutter.dev/flutter/material/Divider-class.html)というクラスがあり、
itemBuilderが、Dividerと、生成した文言の詰まった[ListTile](https://api.flutter.dev/flutter/material/ListTile-class.html)を順番に返して画面に水平線と社名候補を順番に出していくのですね。
![IMG_20191201_180115.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56357/225e8c3c-a2dd-e355-bb1d-b792b3bcf517.jpeg)
確かにじゃんじゃんスクロールできます。

さて、ここまでAndroid実機を使っていましたが、"flutter run -d all"　で、複数のデバイスを同時に起動できることがわかったので、iOSシミュレーターも起動してみました。
<img width="495" alt="スクリーンショット 2019-12-01 18.08.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56357/66e43d20-5f77-4c7e-17b5-d545aea4d62c.png">

rを押すとhot reloadが走り、両方のアプリが更新されました。一つのコードでiOS/Androidのネイティブアプリが動いていて、コード修正するたびに両方に反映される、って不思議な体験ですね。(12/1 18:30に書いています)

そろそろ夕食の時間なので、今回はここまでとします。

# あとがき

公式サイトのGet Startedのおかげで、環境構築から、Android/iOSで同じコードで同じアプリを動かすところまで、記事を書きつつ半日でたどり着けました。まだページ遷移も、スクロール以外のインタラクションも、外部通信もない、ペラっとしたアプリを動かしただけですが、Flutter, Dartの雰囲気をちょっとだけ感じることができました。英語ではありますがドキュメントも充実していそうな感じでした。

予定していた記事が書けず、苦し紛れにやってみたFlutter、思いのほか面白かったです。はじめて自分でネイティブアプリを作って、それが実機で動いているというのは特別な体験でした。年末のお休みに向けて新しいおもちゃを手に入れた気分です。まさにAdvent Calendarですね。

明日は@gggkさんの、【Rails】コーディング時に気をつけるべきこと　です。明日もお楽しみにどうぞ。