Closed14

Flutterを勉強し始めたので知ったことをメモしていく その2

ichi3wichi3w

その1 から続く
https://zenn.dev/ichi3w/scraps/8d53984a48205d

このスクラップでは、Flutterを勉強し始めて知ったことを、つらつら垂れ流してみます。
目的は、知ったことを忘れないようにメモしておくことです。
もしかしたら、ざっと辿っていただけると、これからFlutterを学ぶ人は、なんとなく全体像が掴めるかもです。
あとは、個人のアウトプットとして垂れ流していくので、間違った情報があるかもです。
ご注意いただければ幸いです🕊
Flutter: 3.24.0
Macbook M1Pro
VisualStudio Code
iOS と Android 向けのアプリを作る

ichi3wichi3w

バタバタしていたけれど再開します。

ひさしぶりにプロジェクトを開くと、flutter 3.24.1が来ていました。
プロジェクトのflutterが 3.22.3 だったので、アップデートしておきます。

fvmをバージョン管理ツールとして使っており、
fvm releases で最新バージョンを確認した後、
fvm install 3.24.1 でインストールし、
fvm use 3.24.1 でプロジェクトのバージョンを固定しました。

(ついでに fvm global 3.24.1 でglobalで使うflutterも上げておきます)
.fvmrc ファイルや fvm flutter --version が上がっていることを確認。

fvm flutter pub get で新しいパッケージをインストールし、
fvm flutter pub update で依存パッケージをアップグレードしました。

ただし、このままだといくつか古いパッケージが残るので、
fvm flutter pub upgrade で依存関係を把握し、
適当に pubspec.yaml で使用しているパッケージのバージョンを更新しました。

ichi3wichi3w

ここで F5 で VSCode を通して /lib/main.dart からアプリを起動。
ビルドが走るのですが、
flutter ios/Runner/AppDelegate.swift uses the deprecated @UIApplicationMain attribute, updating.
と注意されているのを発見。

以下の通りに解決。
https://stackoverflow.com/questions/78848018/ios-runner-appdelegate-swift-uses-the-deprecated-uiapplicationmain-attribute-af

とりあえず、バージョンアップはこんな感じで。
あとは作り始めて、必要に応じて追加で理解度をあげていくことにします。

ichi3wichi3w

ページの切り替えについて考えていて、まあ、とにもかくにも状態管理が必要そうです。
prividerというのがよく使われていたらしいですが、riverpodが流行ってきているらしいので、こちらを採用しました。

flutter pub add flutter_riverpod でインストールしてもいいし、直接 pubspec.yaml を編集した後、flutter pub get してもいいそうです。

ichi3wichi3w

flutterのディレクトリ構成ですが、/libディレクトリにプログラムを書いていくようです。
/ios/android などはネイティブコードやそれぞれのプラットフォームに向けた設定ファイルが置かれるとのこと。

ichi3wichi3w

/lib内のディレクトリ構成ですが、ひとまず ファイルタイプで分けることにしました。
viewsやwidgetsフォルダを作ります。

機能別(authとかarticleとか)やドメイン別で分けてもいいのですが、ひとまず、、。

ichi3wichi3w

基本的に、lintがしっかり仕事してくれているのか、やばそうなところはwarningが出ます。
例えば、Constructors for public widgets should have a named 'key' parameter. Try adding a named parameter to the constructor. などです。
これはクラスに keyをつけてね、とのこと。

class ArticleDetailPage extends ConsumerWidget {
  const ArticleDetailPage({super.key});
  ...

のように const ArticleDetailPage({super.key}) を書いておきます。
このsuper.keyは const ArticleDetailPage({Key? key}) : super(key: key); と同じだそうです。
(2.2くらいから追加された書き方でこちらを使うのを推奨らしい)

あとは、constを使えだの、丁寧に叱ってくれるので、大人しく従います。

ichi3wichi3w
class MyApp extends StatefulWidget {
  const MyApp({super.key});

  
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int _currentIndex = 0;
  final List<Widget> _pages = [
  ...

StatefulWidgetにて、このように書いていたら、MyAppクラスの _MyAppStateのところで怒られました。

どうも_アンダースコアで始まるクラス名はprivateになるらしく、createState()もprivateにしなさいよ(もしくは_MyAppStateをpublicにしなさいよ)とのことです。

これは、 State<MyApp> createState() => _MyAppState(); のように書くといいとのことです。

ichi3wichi3w

NavigationBarを BottomNavigationBar ウィジェットを使い実装。
ここら辺は探せばたくさん出てきそうなので割愛。

ichi3wichi3w

ページ遷移に関しては、Navigator 2.0 による方法もあるようです。
今回はタブの選択に応じて遷移したかったのでRiverpodによって実装しました。

ichi3wichi3w

次に、Homeに適当な画像をメインビジュアルとして配置してみることにします。

画像を扱う方法について

  1. pubspec.yamlにassetsとして登録
flutter:
  assets:
    - assets/images/

このようにディレクトリごと設定することもできるようです。
(ただし、子ディレクトリのファイルまでは見に行ってくれない模様)

  1. Image.asset('MY_IMAGE_PATH') のように呼び出す

なお、Image.assetウィジェットはconstをつけることができません。
これは画像が表示される時に動的に評価されるため(ディスプレイに応じたサイズ等)、コンパイル時には評価できないからだそうです。

また、もしウェブ上の画像を表示するときは、Image.networkを使うとのこと。

メモ

  • 2x/3x/のようにディレクトリを作ると、解像度ごとに異なる画像を使ってくれるらしい
  • LazyLoadingができるらしい
  • キャッシュが多くならないよう、メモリクリアしたり
  • Placeholderを使ったり
ichi3wichi3w

黙々とページを作っていきます。
使ったウィジェットをまとめておきます。

・Card ウィジェット
子を持てる。marginつけたり、影を設定したり、constをつけたり、便利に使える

・Container ウィジェット
実行時にインスタンスを生成するらしい。Cardより柔軟に設定できるらしい。

・Row, Column
childrenを並べる。デフォルトだと子要素が一行に収まらないとオーバーフローする。
子要素にExpandedやWrapなどを使って対応。

・Wrap
childrenを並べる。子ウィジェットがスペースに収まりきらない場合、自動的に折り返してくれる。
axisで方向を指定する。

・Expanded
RowやColumn内で使われると、親の残りのスペースを占有する。
flexプロパティで柔軟に比率でスペースを配分することも。
子要素がTextなら、overflow: TextOverflow.ellipsisで省略記号を表示できる。

・SingleChildScrollView
子要素がスクロールできるようになる。

ichi3wichi3w

CMSから記事を取得して表示する機能が欲しいです。

  1. lib/models/article.dart に記事classを作成
  2. lib/mocks/mock_articles.dart にモックデータを作成
  3. lib/views/article_list_page.dart でこれらを使って一覧を表示
  4. 一覧をクリックすると、lib/views/article_detail_page.dart で詳細を表示する

という流れで記事一覧を作成しました。

なお、article_list_item.dartを作って、Listの一要素を別ファイルに分離させました。
いい感じにウィジェットは分けていきたいです。

また、タップした時のアクションは、

GestureDetector(
  onTap: () {
    // 記事がクリックされた時に詳細ページへ遷移
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => ArticleDetailPage(article: article),
      ),
    );
  },
  child: Card(
    // ...

のように、 GestureDetector を使うといいようです。

ichi3wichi3w

CMSから取得した記事の本文は、htmlで書かれています。
flutterでは、flutter_html というパッケージを使ってhtmlの要素をflutterのウィジェットに変換して表示できるそうです。

ただし、 flutter_html は2年前から更新が止まっており、新しいflutter 3.24.1では動きませんでした。
そこで、 flutter_widget_from_html を使いました。

pubspec.yaml に追記。

dependencies:
  flutter_widget_from_html: ^0.15.2

flutter pub get でパッケージ更新。

なお、 webview_flutter で表示することもできるようです。
こちらは直接ウェブとして表示できるので、style等をウェブの表示と合わせやすいそうですが、レンダリングがやや遅いとのこと(ざっくり理解だが、ブラウザを用意してそこにレンダリングするかららしい)。

実際にどのくらい遅いのかわからない(気にならないくらいな気がする)のですが、ひとまずflutter_widget_from_htmlを試していくことにします。

他には、markdownから表示するパッケージもあるとのこと。

このスクラップは3ヶ月前にクローズされました