mcpField
F
flutter-dev

flutter-dev

github.com/bogdanustyak開発0176 回インストール40 週間前に更新
リポジトリ

flutter-dev について

Flutter チームの実践に沿って、Flutter と Dart の開発を支援するスキルです。コード構成、状態管理、レイアウト、ナビゲーション、テスト、アクセシビリティを扱います。

主な機能

  1. 01SOLID と Dart のスタイル規約
  2. 02レイヤー別または機能別の構成
  3. 03組み込み状態管理の選択指針
  4. 04レスポンシブレイアウトとナビゲーション
  5. 05テストとコード解析の推奨事項
  6. 06アクセシビリティとテーマ設計

活用シーン

  1. 01Flutter プロジェクト構成の計画
  2. 02レスポンシブ UI とナビゲーションの実装
  3. 03状態管理と非同期処理の選択
  4. 04アプリのテストとコード解析

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/bogdanustyak/flutter-expert-skill --skill flutter-dev

インストール後、Claude Code で/flutter-devを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
references/
navigation_patterns.md
theme_patterns.md
state_patterns.md

詳細

Flutter 開発エキスパート

Flutter チームの公式ベストプラクティスに沿った、Flutter と Dart 開発の専門的なガイダンスです。

開発の基本原則

コードの理念
  • コードベース全体に SOLID 原則を適用します
  • 関数型および宣言型のパターンを取り入れた、簡潔でモダンかつ技術的な Dart コードを書きます
  • 複雑なウィジェットやロジックを構築する際は、継承よりもコンポジションを優先します
  • 特にウィジェットには不変のデータ構造を優先します(可能な限り StatelessWidget を使用します)
  • 適切な状態管理を使用して、一時的な状態とアプリの状態を分離します
  • 関数は単一の目的を持つ短いものにします(20 行未満を目指します)
  • 意味が明確で説明的な名前を付け、省略形は避けます
プロジェクト構造の前提
  • エントリーポイントを lib/main.dart とする標準的な Flutter プロジェクト構造
  • 論理的なレイヤーごとに整理します:プレゼンテーション(ウィジェット/画面)、ドメイン(ビジネスロジック)、データ(モデル/API クライアント)、コア(ユーティリティ/拡張機能)
  • 大規模なプロジェクトでは、機能ごとに整理し、各機能にプレゼンテーション/ドメイン/データのサブフォルダーを設けます

対話のガイドライン

コードを生成する際:

  • null safety、futures、streams など、Dart 固有の機能について説明します
  • 依頼が曖昧な場合は、機能と対象プラットフォームについて確認します
  • pub.dev の新しい依存関係を提案する場合は、その利点を説明します
  • 一貫したフォーマットを適用するために dart format ツールを使用します
  • よくあるエラーを自動修正するために dart fix ツールを使用します
  • 問題を検出するために、推奨ルールを適用した Dart リンターを使用します

コード品質基準

スタイルのルール
  • 行の長さ:80 文字以下
  • 命名規則:
    • クラスには PascalCase
    • メンバー/変数/関数/enum には camelCase
    • ファイルには snake_case
  • 行末コメントは使用しません
  • シンプルな 1 行関数にはアロー構文を使用します
エラー処理
  • 潜在的なエラーを予測して処理し、決して黙って失敗しないようにします
  • 適切な例外型を使った try-catch ブロックを使用します
  • コード固有の状況にはカスタム例外を使用します
  • 堅牢なエラー処理を伴う、適切な async/await の使用
ドキュメント
  • すべての公開 API(クラス、コンストラクター、メソッド、トップレベル関数)に dartdoc コメントを追加します
  • 複雑なコードや自明でないコードには、わかりやすいコメントを書きます
  • ドキュメントコメントには /// を使用します
  • 句点で終わる 1 文の要約から始めます
  • コードが何をするかではなく、なぜそのように書かれているかをコメントします

Dart のベストプラクティス

型システムと null safety
  • sound null safety に準拠したコードを書きます
  • Dart の null safety 機能を活用します
  • 値が null でないことが保証されない限り、! 演算子を避けます
  • コードを簡潔にできる場合は、パターンマッチング機能を使用します
  • クラスを定義するのが煩雑な場合は、複数の型を返すためにレコードを使用します
  • 網羅的な switch 文/式を優先します(break は不要です)
非同期プログラミング
  • 単一の非同期処理には Future、async、await を使用します
  • 非同期イベントのシーケンスには Stream を使用します
  • 非同期処理で適切にエラーを処理します
クラスとライブラリの整理
  • 関連するクラスは同じライブラリファイル内に定義します
  • 大規模なライブラリでは、単一のトップレベルライブラリから小さなプライベートライブラリをエクスポートします
  • 関連するライブラリは同じフォルダーにまとめます

Flutter のベストプラクティス

ウィジェットの設計
  • ウィジェット(特に StatelessWidget)は不変です
  • UI を変更する必要がある場合、Flutter はウィジェットツリーを再構築します
  • 既存のウィジェットを拡張するより、小さなウィジェットを組み合わせることを優先します
  • ウィジェットを返すプライベートなヘルパーメソッドではなく、小さなプライベート Widget クラスを使用します
  • 大きな build() メソッドは、再利用可能な小さなプライベート Widget クラスに分割します
  • 再構築を減らすため、可能な限り const コンストラクターを使用します
パフォーマンスの最適化
  • 長いリストには ListView.builder または SliverList を使用します(遅延読み込み)
  • コストの高い計算(JSON の解析など)を別の isolate で実行するには、compute() を使用します
  • build() メソッド内で、コストの高い処理(ネットワーク呼び出し、複雑な計算)を避けます
  • 再構築を最小限に抑えるため、build() メソッド内で const コンストラクターを使用します
レスポンシブデザイン
  • レスポンシブな UI には LayoutBuilder または MediaQuery を使用します
  • さまざまな画面サイズに対応したモバイル向けデザインにします
  • モバイルと Web の両方のプラットフォームでテストします

状態管理

サードパーティ製のソリューションを明示的に求められていない限り、Flutter 組み込みのソリューションを優先します。

組み込みソリューション(シンプルな順)
  1. ValueNotifier + ValueListenableBuilder - 単一の値を扱うシンプルなローカル状態
final ValueNotifier<int> _counter = ValueNotifier<int>(0);

ValueListenableBuilder<int>(
  valueListenable: _counter,
  builder: (context, value, child) => Text('Count: $value'),
);
  1. ChangeNotifier + ListenableBuilder - 複数のウィジェット間で共有する複雑な状態
class CounterModel extends ChangeNotifier {
  int _count = 0;
  int get count => _count;
  void increment() {
    _count++;
    notifyListeners();
  }
}

ListenableBuilder(
  listenable: counterModel,
  builder: (context, child) => Text('${counterModel.count}'),
);
  1. Streams + StreamBuilder - 非同期イベントのシーケンス
  2. Futures + FutureBuilder - 単一の非同期処理
高度なパターン
  • MVVM:堅牢なアプリケーション向けの Model-View-ViewModel パターン
  • 依存性注入:依存関係を明示するため、手動でコンストラクター注入を使用します
  • Provider:手動注入を超える DI を明示的に求められた場合にのみ使用します

ナビゲーション

GoRouter(推奨)

宣言的なナビゲーション、ディープリンク、Web サポートには go_router を使用します。

// Add dependency
flutter pub add go_router

// Configure router
final GoRouter _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomeScreen(),
      routes: [
        GoRoute(
          path: 'details/:id',
          builder: (context, state) {
            final String id = state.pathParameters['id']!;
            return DetailScreen(id: id);
          },
        ),
      ],
    ),
  ],
);

// Use in MaterialApp
MaterialApp.router(routerConfig: _router);
  • 認証フローには redirect プロパティを設定します
  • ディープリンク可能なルートに使用します
Navigator(組み込み)

ディープリンクが不要な短時間表示の画面(ダイアログ、一時的なビュー)に使用します。

Navigator.push(context, MaterialPageRoute(builder: (context) => DetailsScreen()));
Navigator.pop(context);

パッケージ管理

pub ツールの使用
  • 依存関係を追加:flutter pub add <package_name>
  • 開発用依存関係を追加:flutter pub add dev:<package_name>
  • オーバーライドを追加:flutter pub add override:<package_name>:1.0.0
  • 依存関係を削除:dart pub remove <package_name>
外部パッケージ
  • pub.dev で適切かつ安定したパッケージを検索します
  • 新しい依存関係を提案する際は、その利点を説明します

データ処理

JSON シリアライズ

json_serializable と json_annotation を使用します。

import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';

@JsonSerializable(fieldRename: FieldRename.snake)
class User {
  final String firstName;
  final String lastName;
  
  User({required this.firstName, required this.lastName});
  
  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}
コード生成
  • build_runner が開発用依存関係に含まれていることを確認します
  • 変更後に実行します:dart run build_runner build --delete-conflicting-outputs

ロギング

構造化ロギングには dart:developer を使用します。

import 'dart:developer' as developer;

// Simple messages
developer.log('User logged in successfully.');

// Structured error logging
try {
  // code
} catch (e, s) {
  developer.log(
    'Failed to fetch data',
    name: 'myapp.network',
    level: 1000, // SEVERE
    error: e,
    stackTrace: s,
  );
}

UI とテーマ

Material Design 3 と ThemeData

調和のとれたカラーパレットには ColorScheme.fromSeed() を使用します。

MaterialApp(
  theme: ThemeData(
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.deepPurple,
      brightness: Brightness.light,
    ),
    textTheme: TextTheme(
      displayLarge: TextStyle(fontSize: 57, fontWeight: FontWeight.bold),
      bodyMedium: TextStyle(fontSize: 14, height: 1.4),
    ),
  ),
  darkTheme: ThemeData(
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.deepPurple,
      brightness: Brightness.dark,
    ),
  ),
  themeMode: ThemeMode.system,
);
カスタムテーマ拡張

標準の ThemeData を超えるカスタムデザイントークンには、次を使用します。

@immutable
class MyColors extends ThemeExtension<MyColors> {
  const MyColors({required this.success, required this.danger});
  final Color? success;
  final Color? danger;
  
  @override
  ThemeExtension<MyColors> copyWith({Color? success, Color? danger}) {
    return MyColors(success: success ?? this.success, danger: danger ?? this.danger);
  }
  
  @override
  ThemeExtension<MyColors> lerp(ThemeExtension<MyColors>? other, double t) {
    if (other is! MyColors) return this;
    return MyColors(
      success: Color.lerp(success, other.success, t),
      danger: Color.lerp(danger, other.danger, t),
    );
  }
}

// Register in ThemeData
theme: ThemeData(
  extensions: [MyColors(success: Colors.green, danger: Colors.red)],
),

// Use in widgets
Container(color: Theme.of(context).extension<MyColors>()!.success)
フォント

カスタムフォントには google_fonts パッケージを使用します。

flutter pub add google_fonts

final TextTheme appTextTheme = TextTheme(
  displayLarge: GoogleFonts.oswald(fontSize: 57, fontWeight: FontWeight.bold),
  titleLarge: GoogleFonts.roboto(fontSize: 22, fontWeight: FontWeight.w500),
  bodyMedium: GoogleFonts.openSans(fontSize: 14),
);
画像とアセット

pubspec.yaml に宣言します。

flutter:
  uses-material-design: true
  assets:
    - assets/images/
// Local images
Image.asset('assets/images/placeholder.png')

// Network images (always include error handling)
Image.network(
  'https://example.com/image.png',
  loadingBuilder: (context, child, progress) {
    if (progress == null) return child;
    return Center(child: CircularProgressIndicator());
  },
  errorBuilder: (context, error, stackTrace) => Icon(Icons.error),
)

レイアウトのベストプラクティス

柔軟なレイアウト
  • Expanded:Row/Column 内の残りのスペースを埋めます
  • Flexible:収まるように縮小します(Expanded と併用しないでください)
  • Wrap:はみ出した場合に自動で次の行に折り返します
  • SingleChildScrollView:ビューポートより大きい固定サイズのコンテンツに使用します
  • ListView.builder/GridView.builder:長いリストに使用します(遅延読み込み)
  • FittedBox:親の範囲内に単一の子を拡大縮小して収めます
  • LayoutBuilder:利用可能なスペースに応じたレスポンシブレイアウトに使用します
Stack レイアウト
  • Positioned:端を基準にして子を正確に配置します
  • Align:アラインメント(例:Alignment.center)を使って配置します
オーバーレイ

すべての要素の上に UI 要素を表示するには OverlayPortal を使用します。

final _controller = OverlayPortalController();

OverlayPortal(
  controller: _controller,
  overlayChildBuilder: (context) => Positioned(
    top: 50,
    left: 10,
    child: Card(child: Text('Overlay content')),
  ),
  child: ElevatedButton(
    onPressed: _controller.toggle,
    child: Text('Toggle'),
  ),
)

ビジュアルデザインの原則

デザインガイドライン
  • モダンなデザインに沿った、美しく直感的な UI を構築します
  • さまざまな画面サイズ(モバイルと Web)に対応させます
  • 直感的に操作できるナビゲーションを提供します
  • タイポグラフィの階層構造(ヒーローテキスト、見出し、キーワード)を使用します
  • さりげない背景テクスチャを適用し、上質な印象を与えます
  • 複数層のシャドウを使用して奥行きを表現します
  • 理解を助けるアイコンを取り入れます
  • インタラクティブな要素には、色のグロー効果を伴うシャドウを付けます
色のガイドライン
  • 60-30-10 ルール:60%をプライマリカラー/ニュートラルカラー、30%をセカンダリカラー、10%をアクセントカラーにします
  • コントラスト比(WCAG 2.1):
    • 通常のテキスト:最低 4.5:1
    • 大きなテキスト(18pt または 14pt の太字):最低 3:1
  • テキストと背景に補色を使うのは避けます(目の疲れの原因になります)
  • アクセントには補色を控えめに使用します
タイポグラフィ
  • フォントファミリーは 1~2 種類に制限します
  • 読みやすさを優先します(UI の本文にはサンセリフ体を使用します)
  • 行の高さ:フォントサイズの 1.4~1.6 倍
  • 本文の行の長さ:45~75 文字
  • 長文ではすべて大文字にするのを避けます

テスト

テストの種類
  • ユニットテスト:ドメインロジック、データレイヤー、状態管理には package:test を使用します
  • ウィジェットテスト:UI コンポーネントには package:flutter_test を使用します
  • 統合テスト:エンドツーエンドのフローには package:integration_test を使用します
テストのベストプラクティス
  • Arrange-Act-Assert(Given-When-Then)パターンに従います
  • より表現力の高いアサーションには package:checks を優先します
  • モックよりフェイク/スタブを優先します
  • モックが必要な場合は、mockito または mocktail を使用します
  • 高いテストカバレッジを目指します
  • テスト可能なコードを記述します。依存性注入には file、process、platform パッケージを使用します
テストの実行
flutter test

アクセシビリティ(A11y)

  • 色のコントラスト:テキストと背景のコントラスト比を最低 4.5:1 にします
  • 動的なテキストサイズ調整:システムのフォントサイズを大きくして UI をテストします
  • セマンティックラベル:明確でわかりやすいラベルを設定するには、Semantics ウィジェットを使用します
  • スクリーンリーダーのテスト:TalkBack(Android)と VoiceOver(iOS)でテストします

解析とリンティング

analysis_options.yaml に以下を含めます:

include: package:flutter_lints/flutter.yaml

linter:
  rules:
    # Add additional lint rules here

追加リソース

詳しいパターンや例については、以下を参照してください:

  • references/navigation_patterns.md - GoRouter を使用した高度なナビゲーションパターン
  • references/state_patterns.md - 状態管理の包括的な例
  • references/theme_patterns.md - 高度なテーマ設定とスタイル設定のパターン

コメント