Flutterを勉強し始めたので知ったことをメモしていく その1
このスクラップでは、Flutterを勉強し始めて知ったことを、つらつら垂れ流してみます。
目的は、知ったことを忘れないようにメモしておくことです。
もしかしたら、ざっと辿っていただけると、これからFlutterを学ぶ人は、なんとなく全体像が掴めるかもです。
あとは、個人のアウトプットとして垂れ流していくので、間違った情報があるかもです。
ご注意いただければ幸いです🕊
Flutter: 3.24.0
Macbook M1Pro
VisualStudio Code
iOS と Android 向けのアプリを作る
Flutter ロードマップ 🏝️
flutter開発環境のセットアップまで
概ね以下の通りでよさそうでした。
flutterのバージョン管理には、FVMを使いました。(ASDFを使うこともできそうです)
brew経由でインストール。
CocoaPods のインストールにruby が必要で、ただmacに入っているデフォルトのものはバージョンが低くて動かなかったので、rbenv でアップデートしました。
CocoaPods は iOS系の開発パッケージを管理してくれるらしいと雑に理解🤔
fvm flutter doctor でうまく動いているかチェックできたので、それに従って XCode や Android Studio を整えていきます。
IDEとしては、VSCodeを使うことにしました(ドキュメントを見ていると一番おすすめっぽかった)。
あとは、開発中のアプリを確認するために、Simulator.app をセットアップ(XCodeについてくるやつ)。実機を使うこともできるので、また開発に慣れてきたところでセットアップします。
fvmの使い方
いかにお世話になりつつ、ざっと使い方を把握しました。
fvm releases
でインストールできるバージョンの一覧がわかります。
その後に、fvm install [VERSION]
でPCにインストールできます。
プロジェクトで使うバージョンを決めるには、ディレクトリに移動して fvm use [VERSION]
をします。
現在設定しているバージョンで、flutterコマンドを使うには、fvm flutter コマンド
のようにします。
また、GLOBALに使えるflutterを設定するには、fvm global [VERSION]
もし、GLOBAL設定を解除するには fvm global --unlink
です。
ただし、あらかじめパスを通しておく必要あるらしいです。
fvm list
で現在インストールしているバージョンがわかります。
fvm doctor
でいろいろ設定がわかります。
プロジェクトの作成
アプリを作成します。
VSCodeの拡張機能を入れていると、確か Command + Shift + P
で flutterのアプリを作成することができました。
ほか、CLIでは以下で作成できました。
(いずれの方法も、flutterの docを参照するとよい)
fvm flutter create [プロジェクト名]
💡プロジェクト名にはハイフンが使えません。プロジェクト名がそのままパッケージ名になり、パッケージ名にはハイフンが使えないからです。
その後、 fvm use 3.24.0 をしてバージョンを固定しました。
正しくできると、gitignoreに.fvmが追加されたり、setting.json、.fvmrcが作成されました。
(これで異なる環境へのシェアできるかわかりませんが、取り急ぎ)
あとは、VSCodeの実行とデバッグから、flutter dart構成を選択しました。
ボタンを適当に押して、launch.jsonを適当に作ってもらいます。
最後に git init
をして、適当にコミットを固めておきます。
💡バックエンドとして機能させるアプリと、このFlutterのアプリをモノレポにして管理したかったのですが、VSCodeのデバッグ機能の構成に不安を覚えたため、リポジトリを分けることにしました。またチャレンジしてみたいところです。
dartについて
オブジェクト指向。
型安全(nullもちゃんとチェックしてくれる)。
さまざまなOSのアプリに対応するためか、class周りでそれなりに高度な表現がありそう?
C# と TypeScript を足して 3で割ったような印象を受けました🤔
以下、気になったところメモ
- C# みたく var で変数を定義でき、自動で型推論してくれる
- Stringとか型がある。型安全
- null許容型じゃないとnullになれない
- final をつけて変数を定義すると今後値を変更できなくなる
- constはコンパイル時の定数
- assartを使えば、開発環境でのみassartできる
- print()でなんかprintできるらしい
- @override @pragma @deprecated @Deprecatedのメタデータがある
- _はプライベート、get,setとかもある
- importは次のような感じ
import 'package:lib2/lib2.dart' as lib2;
- コレクションやintやmapやrecordなどの型がある
- ジェネリックもある
- 型定義はtypedefやけど、ほとんどの場合インライン関数で宣言するのがおすすめ
- パターンマッチングとかできる。
var (a, [b, c]) = ('str', [1, 2]);
- 真のオブジェクト指向でFunction型もある
- ループやifもある
- エラーを投げたりtry catch でき、
} on OutOfLlamasException {
のようにExceptionに応じて処理もできる - dartのdevtoolがあるっぽいが、また調べる( https://dart.dev/tools/dart-devtools )
dartのパッケージについて
pubパッケージマネージャで管理されているとのこと
よく使われるパッケージ
Flutterの書き方をちょっと理解できたら、どんなものがあるか頭にざっと入れておきたいと思います。
アプリをデバッグで立ち上げる
Command + Shift + P のち「Flutter: Select Device.」を選択します。
もしくは、flutter devices
コマンドで、使用できるデバイスを表示、選択します。
あとは F5 もしくは flutter run
でデバッグを開始できました。
hot reloadあります!やったね!
(VSCodeなら hot reloadをクリック。cliから立ち上げた場合 r を入力)
追記
lib/main.dart を開いて、VSCodeの画面右上の虫さんをクリックでも、アプリが起動するらしい。
はじめてのFlutterアプリ 1〜4くらい
以下をやっていきます。
ひとまず 1〜4ぐらい。- pubspec.yaml に現在のバージョン、依存関係など、アプリの基本情報があります
- pubspec.yaml のdependencies を更新したら、自動でパッケージもダウンロードされました
- analysis_options.yaml に lint設定があります
- lib/main.dart から起動します
print('button pressed!'); をしたら、devtoolにログが出てきました。
ログがちゃんと出ると嬉しいですね。
ウィジェットはFlutterアプリを作成する際に、元となる要素とのこと。
ここら辺で、ウィジェットを組み合わせてアプリを作るのだと閃く!
buildメソッドはウィジェットか、ウィジェットのネストしたツリーを返します。
サンプルアプリでは、ChangeNotifierを継承して、MyAppStateクラスを作り、アプリの状態管理をしています。そして、各ウィジェットのbuildメソッドで、watchするようです。
ここらへんまでは、手続き型と宣言型が混ざったような感じでちょっと不思議です。
今回出てきたウィジェット
- StatelessWidget
- なんかアプリの大元になるやつ
- Scaffold
- なんか足場になるらしいやつ。便利でよく使われる
- Column
- 上から下へ、任意の数の子🐟を並べてくれる
- Text
- その名の通り文字を表示する
- ElevatedButton
- 何が Elevate かわからないが、とりあえずボタン。他のボタンが出てきた時に、このこの特徴もわかるはず
はじめてのFlutterアプリ その4〜5くらい
VSCodeのエディターでTextを右クリックして「リファクター > Extract Widget」をすると何ということでしょう、ウィジェットとして分離されました。
同じくリファクターで「Wrap with Padding」を選択すると、Paddingウィジェットが追加されました。
Flutterではできる限り継承ではなく合成をするらしい。
PaddingがTextの属性ではなく、ウィジェットとして分かれているのもそのためとのこと。
(..Flutterが少し好きになった)
リファクタ、でええ感じにしてくれるのはありがたいですね。
リファクタをぽちぽちしているだけで、知識が増えそうです。
ショートカットは「Ctrl + Shift + R」。
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Card(
color: theme.colorScheme.primary,
child: Padding(
// ...
のようにThemeから色を取り出して当ててみたり
色の変化を暗黙的にアニメーションくれるので、Themeを使うと良いそうです。
あとは、fontSizeを
final style = theme.textTheme.displayMedium!.copyWith(
color: theme.colorScheme.onPrimary,
);
で指定したり。
themeに何を設定しておくか、結構重要そうですね。
semanticsLabel でスクリーンリーダーに対応するらしい。
Semantics というウィジェットもあるらしく、アクセシビリティは結構重要視されているとのこと。
mainAxisAlignment: MainAxisAlignment.center,
を Column ウィジェットに設定すると、コンテンツを中央に配置できた。
おそらく、レイアウト用のウィジェットが他にもありそう。
あとは、devtool の Widget Inspector で Chromeの開発ツールみたく、要素の位置を見れました。
devtool を活用できるかで、けっこう得られる情報が増えそうなので、しっかり触っておきたい気がします。
今回出てきたウィジェット
- Card
- カードっぽい見た目になる
- Padding
- Paddingを入れてくれる
- Center
- 中央に寄せてくれる
- SizedBox
- 要素間スペースを
その他
適当に const やら final を使うと、メモリとかええ感じになってアプリが軽くなるらしいです。
うまく使っていく。
はじめてのFlutterアプリ その6
ビジネスロジックが現れたぞ! 編。
ジェネリクスを使って、 WordPair 以外が入らないようにした例。
var favorites = <WordPair>[];
型がある幸せの中で僕たちは生きていく。
mainAxisSize: MainAxisSize.min,
これで、そのコンポーネントのAxis のサイズを設定できました。
Center だったり、 mainAxisAlignment だったり、色々なサイズがある。
UWP の HorizontalAlignment とか、 CSS の flex とか、中央寄せ関係は「子要素にかかるか、自分の位置に影響するか」を掴むと早いと思っている。
ElevatedButton.icon(
onPressed: () {
appState.toggleFavorite();
},
icon: Icon(icon),
label: Text('Like'),
),
appStateでは、notifyListenersでイベントを発しているぽい。
Reactみたく全自動(?)ではないが、UWPみたく長ったらしくPropertyChangedを作ったりせずともOK。
Flutterがまた好きになった。
ところで、appStateはどれくらいの粒度で分けておくのが幸せなのだろうか?
新しいウィジェット
- Row
- Columnがあれば、Rowもあるよね
はじめてのFlutterアプリ その7
ナビゲーションウィジェット編。
これで迷子にならずに済むのか、それとも迷子が発生する原因となるのか。
ナビゲーションを作るために。
よしなに SafeArea と Expanded を Row で振り分けながら、NavigationRail や これまでに作ってきたページを配置しました。
そして、ページは後述の ステートフルウィジェット をうまく使いながら、selectedIndex で切り替えていきます。
ステートレス ウィジェットとステートフル ウィジェット
これまではどのウィジェットも、自身にステートを持っていなかった。
すべて、ChangeNotifier を継承した、 MyAppState クラスを通して、状態を変化させていました。
せやかて Global な State を作りすぎると大変な目にあうことはわかっています。
そこで、 MyHomePage をステートフルに変えて、よしなにするらしい。
リファクタ機能を使い、ステートフルに変えると、_MyHomePageStateというプライベートなクラスが作られました。
これは State を拡張しているらしいです。
そして NavigationRail の
onDestinationSelected: (value) {
setState(() {
selectedIndex = value;
});
},
で 選択された アイテムに切り替えるとのこと。
(setState 、、君はflutterにもいると思っていたよ、という気持ちです)
(flutterのStateクラスは、UWPのViewModel でよく使われる Observable class と似ているかも)
あとはええ感じに Widget の変数を作って、そこにページを入れて使ったらナビが機能するように。
ナビゲーションをレスポンシブ対応
大きさの単位として、flutterは論理ピクセルを使うとのこと。
ナビゲーション レール は画面のサイズを認知できないため、LayoutBuilder を使って、600px以上のサイズなら extended を trueにしてやります。
今回のナビゲーションレールでは使えませんが、ほかにもWrapやFittedBoxというウィジェットもあるらしいです。
今回出てきたウィジェット
- SafeArea
- その子がハードウェアノッチやステータスバーで隠れないようにしてくれる
- NavigationRail
- いわゆるナビゲーションバー
- いくつかの Destination を含める
- NavigationRailDestination でナビのアイテムを作れる
- onDestinationSelected で Destination が選択された時に何が起きるかを書ける
- Expanded
- ええ感じにスペースを埋めてくれる。RowやColumnと仲良し
- Container
- 色のついたコンテナとか作れるよ
- Placeholder
- 名は体を表す
- Wrap
- 十分なスペースがない時に、自動的に次の行に子を送ってくれる
- FittedBox
- 指定に従って子を自動的に合わせる
- LayoutBuilder
- 画面サイズの制約に変更があった場合、builder コールバックが呼ばれる
気づき余談
ネスト祭りになりやすいぽい。
はじめてのFlutterアプリ その8
力試しとして、Favoritesを表示するページを作る。
以上
UWPやReactに触れたことはあるので、ウィジェットを使うとか、Stateを持たせるとか、宣言的UIとかは馴染みがありました。
慣れと覚えることはいくつかありそうだけど、とりあえず作り始めれそうです。
わからないことをざっとメモ
- アプリが大きくなるにつれ、ハマりそうなことは?
- 制約周りはまだ慣れが必要そう
- MaterialUIを使うのでいいのか
- ページとか別のファイルに分けたいな
- 多人数の開発において、lintとかformatterとかどうしておくといいか?
- 通信と非同期まわりのこと
- データの永続化のこと
- devtool使いこなす
- テスト周り
- OS特有の機能
- アプリの公開について
アンチパターンをネットで拾っておきつつ、flutterのdocにざっと目を通し、作りたいものを作っていきながら調べる方向でいきます。
ブラウザのタブのロゴで、FlutterとZennを見間違える。
クパチーノとMaterial 3、どっちを使えばいいのだろうか、、?
さらに pub.dev には多くのデザインシステムもあるらしい🤔
デザインなだけで、使えるコンポーネントには差がない、と思いたいところです。
もし、Material 3 でしかできないことがあるなら辛いなぁと。
GoogleなのでMaterial 3を使っておけば、間違いなさそうですが、クパチーノを使いたい気持ちもあります。
そしてウィジェット一覧
状態管理もいろいろあるらしい
- Provider
- Riverpod
- Bloc
- setState
「flutter 状態管理 2024」で検索すると、Riverpodがよく出てきたので、流行っているのかも?
追記: 私見とおっしゃられているが、以下がわかりやすかった。感謝
ひとまず以下の通りで試してみよう。
デザインシステムはAndroidとiOSともに対応したいので、MaterialUIを使う。
それでいて、徐々に自作のthemeで上書きしてやる。
状態管理(依存性注入)は新しすぎず、よく使われてそうな Provider と setState で。
なんとなくできそう感が出てきたので、ここまでとします。
その2