mcpField
F
flutter-design

flutter-design

github.com/anilcancakirデザイン・UI5117 回インストール40 週間前に更新
リポジトリ

flutter-design について

mobile-app-design-mastery スキルを補完する Flutter・Dart 実装ガイドです。テーマ、タイポグラフィ、余白、ウィジェットのパターンでデザイン方針をコードに落とし込みます。

主な機能

  1. 01ThemeData と ColorScheme のパターン
  2. 02TextTheme によるタイポグラフィ指針
  3. 03再利用可能な余白定数
  4. 04BoxDecoration のレシピ
  5. 05ThemeExtension のパターン

活用シーン

  1. 01Flutter 画面へのデザイン方針の適用
  2. 02既存プロジェクトのテーマ設定の利用
  3. 03一貫したカードや入力欄の作成

インストール

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

$npx skills add https://github.com/anilcancakir/my-claude-code --skill flutter-design

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

同梱ファイル

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

references/
extensions.md
theming.md
widgets.md

詳細

Flutter Design Patterns

mobile-app-design-mastery スキルを補完する Flutter/Dart 実装ガイドです。Refactoring UI の原則を Flutter コードに反映します。

前提条件: このスキルでは Flutter 固有の構文を説明します。モバイルデザインの理論や意思決定については、mobile-app-design-mastery スキルを参照してください。


⚠️ 重要:まずプロジェクトのテーマを確認する

新しいスタイルを作成する前に、既存のテーマ設定を必ず確認してください。

プロジェクトに ThemeData、AppColors、AppTextStyles などがある場合は、それらを使用してください。

// Check lib/core/theme/ or lib/config/
// Common patterns:
AppColors.primary
AppTextStyles.headline
AppSpacing.md
context.theme.colorScheme.primary

優先順位:

  1. プロジェクトで定義されたテーマ(AppColors、AppTextStyles、カスタム ThemeExtension)
  2. Theme.of(context) によるアクセス
  3. 最後の手段としてのみハードコード値を使用

ThemeData の設定(Material 3)

MaterialApp(
  theme: ThemeData(
    useMaterial3: true,
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.blue, // Brand color
      brightness: Brightness.light,
    ),
    textTheme: _textTheme,
  ),
  darkTheme: ThemeData(
    useMaterial3: true,
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.blue,
      brightness: Brightness.dark,
    ),
    textTheme: _textTheme,
  ),
);

色へのアクセスパターン

// ✅ CORRECT: Use ColorScheme
final colors = Theme.of(context).colorScheme;
Container(color: colors.primary)
Text('Hello', style: TextStyle(color: colors.onSurface))

// ✅ With extension
extension BuildContextX on BuildContext {
  ColorScheme get colors => Theme.of(this).colorScheme;
}
// Usage: context.colors.primary

// ❌ AVOID: Hardcoded colors
Container(color: Colors.blue) // Ignores theme

ColorScheme の役割:

役割ライトモードダークモード用途
primaryブランドカラー明るいブランドカラーCTA、アクティブ状態
onPrimary白暗色primary 上のテキスト
surface白グレー-900カード、シート
onSurfaceグレー-900白本文
surfaceContainerHighestグレー-100グレー-800高さのあるサーフェス
outlineグレー-400グレー-600境界線
error赤明るい赤エラー状態

タイポグラフィ(TextTheme)

Material 3 のタイプスケール:

スタイルサイズ(sp)用途
displayLarge57ヒーローテキスト
displayMedium45大きなディスプレイ
displaySmall36ディスプレイ
headlineLarge32大見出し
headlineMedium28ページタイトル
headlineSmall24セクションタイトル
titleLarge22カードタイトル
titleMedium16サブタイトル
titleSmall14小さなタイトル
bodyLarge16強調する本文
bodyMedium14標準の本文
bodySmall12補足テキスト
labelLarge14ボタン
labelMedium12ラベル
labelSmall11キャプション
// ✅ CORRECT: Use TextTheme
Text('Title', style: Theme.of(context).textTheme.headlineMedium)

// With extension
extension BuildContextX on BuildContext {
  TextTheme get textTheme => Theme.of(this).textTheme;
}
// Usage: context.textTheme.bodyMedium

余白システム(4dp グリッド)

再利用可能な余白定数を作成します。

abstract class AppSpacing {
  static const double xs = 4;
  static const double sm = 8;
  static const double md = 12;
  static const double base = 16;
  static const double lg = 24;
  static const double xl = 32;
  static const double xxl = 48;
  
  // SizedBox shortcuts
  static const SizedBox gapXs = SizedBox(height: xs, width: xs);
  static const SizedBox gapSm = SizedBox(height: sm, width: sm);
  static const SizedBox gapMd = SizedBox(height: md, width: md);
  static const SizedBox gapBase = SizedBox(height: base, width: base);
  static const SizedBox gapLg = SizedBox(height: lg, width: lg);
}

// Usage
Padding(padding: EdgeInsets.all(AppSpacing.base))
Column(children: [widget1, AppSpacing.gapMd, widget2])

BoxDecoration のパターン

カード(フラット)
Container(
  decoration: BoxDecoration(
    color: colors.surface,
    borderRadius: BorderRadius.circular(12),
    border: Border.all(color: colors.outline.withOpacity(0.2)),
  ),
)
カード(立体)
Container(
  decoration: BoxDecoration(
    color: colors.surface,
    borderRadius: BorderRadius.circular(12),
    boxShadow: [
      BoxShadow(
        color: Colors.black.withOpacity(0.08),
        blurRadius: 10,
        offset: const Offset(0, 2),
      ),
    ],
  ),
)
入力フィールド
Container(
  decoration: BoxDecoration(
    color: colors.surface,
    borderRadius: BorderRadius.circular(8),
    border: Border.all(color: colors.outline),
  ),
)

シャドウのスケール

abstract class AppShadows {
  static List<BoxShadow> sm = [
    BoxShadow(
      color: Colors.black.withOpacity(0.05),
      blurRadius: 4,
      offset: const Offset(0, 1),
    ),
  ];
  
  static List<BoxShadow> md = [
    BoxShadow(
      color: Colors.black.withOpacity(0.08),
      blurRadius: 8,
      offset: const Offset(0, 2),
    ),
  ];
  
  static List<BoxShadow> lg = [
    BoxShadow(
      color: Colors.black.withOpacity(0.1),
      blurRadius: 16,
      offset: const Offset(0, 4),
    ),
  ];
  
  static List<BoxShadow> xl = [
    BoxShadow(
      color: Colors.black.withOpacity(0.15),
      blurRadius: 24,
      offset: const Offset(0, 8),
    ),
  ];
}

// Usage
Container(decoration: BoxDecoration(boxShadow: AppShadows.md))

アンチパターン

// ❌ NEVER
Colors.blue                    // Hardcoded, ignores theme
TextStyle(fontSize: 16)        // Not from TextTheme
SizedBox(height: 17)           // Off 4dp grid
EdgeInsets.only(top: 20, left: 8)  // Asymmetric without reason

// ✅ INSTEAD
context.colors.primary
context.textTheme.bodyLarge
SizedBox(height: 16)           // On grid
EdgeInsets.all(16)             // Symmetric

参考ファイル

トピックファイル
ThemeData と ColorSchemetheming.md
ウィジェットのレシピwidgets.md
ThemeExtension のパターンextensions.md

コメント