Open4

Flutter触ってみる2

chamochamo

その前に

package 管理ツールを fvm から mise(ミーズ) に変更する。

fvm がメジャーバージョン上がって管理方法がかなり変わって melos を使うことが厳しくなってしまったので。
mise は asdf の上位互換らしく、Node も管理できるようなのでこの際完全移行してみる。
(Node は元々 Volta 使ってた。asdf は前使ってたけど独自コマンドが慣れなかった…)

https://mise.jdx.dev/

mise とはの記事
https://zenn.dev/teppeis/articles/2024-01-introduce-mise

mise のインストール

$ brew install mise

https://formulae.brew.sh/formula/mise

Flutter を使えるようにする

Flutter はコミュニティが作成したプラグインを利用して入れる
https://github.com/mise-plugins/registry

$ mise use flutter

この時、 not found jq のようなエラーが出るので、Homebrew 経由で jq をインストールする。
理由はよく分からないけど、asdf 側の package をインストールしているからな気がする。

$ brew install jq

こんな感じで.config/mise/config.toml に package が追加される

config.toml
[tools]
node = "20"
dart = "latest"
flutter = "latest"

余談

そういえば ni はこのまま使えるのだろうか…
試してみないと。

→消えてたから入れ直した。

https://www.npmjs.com/package/@antfu/ni

chamochamo

アプリ作る

flutter create する

$ flutter create list_app

ディレクトリ構造を変更する

こういう形にする

ディレクトリ構造
├── README.md
├── analysis_options.yaml
├── apps
│   ├── android
│   ├── build
│   ├── ios
│   ├── lib
│   │   └── main.dart
│   ├── macos
│   ├── pubspec.lock
│   ├── pubspec.yaml  // このファイルがないと、`flutter run` ができないので注意
│   ├── test
│   └── web
├── build
│   ├── 6b91c21d771f2f2637176955b70f5e34
│   ├── 955b378217de5a8ba81613eebb4bdc77
│   ├── ios
│   └── last_build_run.json
├── list_app.iml
├── melos.yaml
├── melos_list_app.iml
├── packages
│   ├── linux
│   └── windows
├── pubspec.lock
├── pubspec.yaml
└── renovate.json

各package をインストールする

  • melos
    モノレポにするときに便利
    後々使いたかったのでインストールしてみた

https://melos.invertase.dev/

  • Riverpod
    状態管理のやつ

https://pub.dev/packages/riverpod

  • freezed
    generator

https://pub.dev/packages/freezed

  • go_router
    ルーティングをいい感じにしてくれる

https://pub.dev/packages/go_router

最終的な pubspec.yaml

pubspec.yaml
pubspec.yaml
name: list_app

environment:
  sdk: '>=3.3.0 <4.0.0'

dev_dependencies:
  flutter_lints: ^3.0.1
  melos: ^4.1.0

flutter:
  uses-material-design: true
apps/pubspec.yaml
apps/pubspec.yaml
name: list_app
description: "A new Flutter project."
publish_to: 'none'
version: 1.0.0+1

environment:
  sdk: '>=3.3.0 <4.0.0'

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.6
  go_router: ^13.2.0
  riverpod: ^2.5.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^3.0.0
  freezed: ^2.4.7

flutter:
  uses-material-design: true
chamochamo

ListView を作成する

既存の API からデータを取得して表示することをゴールにしたいので

  • 取得したデータをリストで表示する
  • 詳細画面への遷移

は必須とする。以下を参考に作成。
https://zenn.dev/kboy/books/ca6a9c93fd23f3/viewer/e2a9c1

最終的なソースコードは以下。

main.dart
import 'package:flutter/material.dart';

import 'next_page.dart';

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Navigator',
      initialRoute: '/',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      routes: {
        '/': (context) => HomeScreen(),
      },
    );
  }
}

class HomeScreen extends StatelessWidget {
  final items = List<String>.generate(10000, (i) => 'Item $i');

  HomeScreen({super.key});

  
  build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
          title: const Text('リスト画面'),
        ),
        body: SizedBox(
          width: double.infinity,
          child: ListView.builder(
            itemCount: items.length,
            itemBuilder: (context, index) {
              return MyListItem(
                title: items[index],
                subtitle: 'サブタイトル',
                iconData: Icons.star,
              );
            },
          ),
        ));
  }
}

class MyListItem extends StatelessWidget {
  const MyListItem(
      {super.key,
      required this.title,
      required this.subtitle,
      required this.iconData});

  final IconData iconData;
  final String title;
  final String subtitle;

  
  Widget build(BuildContext context) {
    return ListTile(
      leading: Icon(iconData),
      title: Text(title),
      subtitle: Text(subtitle),
      trailing: const Icon(Icons.arrow_forward_ios),
      onTap: () {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => NextPage(title),
          ),
        );
      },
    );
  }
}

メモ

共通のリストクラスを作成したけど、本当ならファイルも分けた方がいいんだろうな〜と。
それは次回の課題にする。
あと、ページ遷移は next_page.dartmain.dart と並列で作成したけど、それも機能ごとに分けた方がいい気がする。
ルーティングは go_router を一つも使えてないので修正する。

にしても、スタイルを全く当てずにリストのUIが作れるのはすごい。(まだちょっと慣れない)