flutter-ui について
Flutter UI 開発向けのスキルです。参照ファイル、チェックポイント、監査スクリプトを使い、状態管理、ナビゲーション、テーマ、レイアウト、アニメーション、パフォーマンスを案内します。
主な機能
- 01実装前に関連資料の確認を要求
- 02インポートから状態管理方式を判定
- 03GoRouter のナビゲーションと戻る処理を案内
- 04テーマ、レイアウト、アニメーションのルールを提示
- 05const とリソース解放をスクリプトで監査
活用シーン
- 01画面ごとの状態管理とナビゲーションを選定
- 02アニメーションの破棄処理と再描画境界を確認
- 03const の不足や非推奨 API を検出
- 04リリース前にテーマ、レイアウト、エラー状態を確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ naimehossein77/ claude-flutter-ui-skills --skill flutter-uiインストール後、Claude Code で/flutter-uiを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
flutter-animations.mdflutter-custom-paint.mdflutter-design-thinking.mdflutter-layout-system.mdflutter-navigation.mdflutter-performance.mdflutter-state-ui.mdflutter-theme-system.mdscripts/flutter_ui_audit.py詳細
Flutter UI システム
理念: Flutter がすべてのピクセルを担います。const を優先します。テーマ駆動です。GPU でアニメーションします。状態のスコープを限定します。
🔧 ランタイムスクリプト
| スクリプト | 目的 | 使用方法 |
|---|---|---|
scripts/flutter_ui_audit.py | 監査:const の不足、dispose のリーク、非推奨 API | python scripts/flutter_ui_audit.py <path> |
🔴 必須:まず参照ファイルを読む
⛔ 関連ファイルを読むまでコードを書かないでください:
| ファイル | 内容 | 優先度 |
|---|---|---|
| flutter-design-thinking.md | 暗記に頼らず、コンテキスト分析を促します | ⬜ 最優先 |
| flutter-state-ui.md | Claude が必ず適用すべき Riverpod と Provider のルール | ⬜ 最優先 |
| flutter-navigation.md | GoRouter、PopScope、戻る処理、ディープリンク | ⬜ 最優先 |
| flutter-animations.md | 暗黙的・明示的アニメーション、Hero、ページ遷移、物理演算 | ⬜ 最優先 |
| flutter-performance.md | const、RepaintBoundary、60fps、シェーダーのウォームアップ | ⬜ 最優先 |
| flutter-theme-system.md | Material 3、ColorScheme、TextTheme、ThemeExtension | ⬜ 読む |
| flutter-layout-system.md | レスポンシブ対応、LayoutBuilder、MediaQuery、スライバー | ⬜ 読む |
| flutter-custom-paint.md | Canvas、CustomPainter、ピクセル単位の描画 | ⬜ 読む |
🧠 まず flutter-design-thinking.md を読む — AI が暗記したパターンを適用してしまうのを防ぎます。
⚠️ 決めつける前に確認する
| 項目 | 確認すること |
|---|---|
| 状態管理 | 「Riverpod、Provider、BLoC、それとも標準機能ですか?」 |
| ナビゲーション | 「GoRouter、auto_route、それとも Navigator 1.0 ですか?」 |
| デザインシステム | 「Material 3、Cupertino、それともカスタムですか?」 |
| プラットフォーム | 「モバイルのみですか、それともタブレット/デスクトップにも適応しますか?」 |
| Flutter のバージョン | 「3.12 以降ですか?(PopScope と WillPopScope の違い)」 |
⛔ アンチパターン
パフォーマンス
| ❌ 絶対にしない | ✅ 必ず行う |
|---|---|
長いリストに静的な子要素を指定した ListView を使う | ListView.builder を使う |
アニメーションループ内で setState を使う | AnimatedBuilder を使う |
非表示にするために Opacity(opacity: 0) を使う | Visibility または条件付きレンダリングを使う |
リスト内で IntrinsicHeight/IntrinsicWidth を使う | 固定の高さまたは SliverFixedExtentList を使う |
StatelessWidget で const を付けない | 常に const MyWidget({super.key}) を使う |
Expanded なしで Column と ListView を組み合わせる | ListView を Expanded で囲む |
ウィジェット内に Color(0xFF...) をハードコードする | Theme.of(context).colorScheme.primary を使う |
fontSize をハードコードする | Theme.of(context).textTheme.bodyLarge を使う |
アニメーション
| ❌ 絶対にしない | ✅ 必ず行う |
|---|---|
width/height をアニメーションする | Transform(拡大縮小/移動)をアニメーションする |
dispose() を呼び出さずに AnimationController を使う | dispose() メソッド内で破棄する |
addListener(() => setState((){})) を使う | AnimatedBuilder を使う |
複雑なペインターに RepaintBoundary を設定しない | CustomPaint を RepaintBoundary で囲む |
| Hero タグを重複させる | データに基づいた一意のタグを使う |
| イージングカーブを設定しない | 最低限 Curves.easeInOut を使う |
ナビゲーション
| ❌ 絶対にしない | ✅ 必ず行う |
|---|---|
WillPopScope を使う(Flutter 3.12 以降では非推奨) | canPop と onPopInvokedWithResult を指定した PopScope を使う |
GoRouter アプリで Navigator.push を使う | context.go()/context.push() を使う |
| ルート文字列を各所にハードコードする | ルート定数を一元管理する |
| 認証画面にルートガードを設けない | GoRouter の redirect コールバックを使う |
| ルート画面で戻るボタンを押しても何もしない | PopScope(canPop: false) と終了確認ダイアログを使う |
状態
| ❌ 絶対にしない | ✅ 必ず行う |
|---|---|
build() 内での ref.read()(Riverpod) | build() 内での ref.watch() |
build() 内での Provider の定義 | トップレベルでの final myProvider = ... |
build() 内での context.read<T>()(Provider) | build() 内での context.watch<T>() |
ChangeNotifier 内での BuildContext | context ではなくデータを渡す |
変更前の notifyListeners() | 先に変更し、その後 notifyListeners() を呼ぶ |
エラーハンドラーなしでの .when() | 常に when(data:, loading:, error:) を使う |
画面全体を囲む Consumer<T> | 最小のウィジェットに Selector<T, R> を使う |
🗺️ ナビゲーション:go() vs push() vs replace()
| メソッド | 戻るスタック | 使用する場面 |
|---|---|---|
context.go('/path') | スタックを置き換える | タブの切り替え、認証後のリダイレクト |
context.push('/path') | スタックに追加する | 詳細画面へのナビゲーション |
context.replace('/path') | 現在の画面を置き換え、ポップしない | 認証後にログイン画面からホームへ |
context.pop() | 現在の画面を削除する | 戻るボタン、モーダルを閉じる |
context.pop(result) | 削除してデータを返す | フォーム送信、ピッカーの結果 |
🎬 アニメーションの選択
WHAT ARE YOU ANIMATING?
├── Simple property change → AnimatedContainer, AnimatedOpacity, TweenAnimationBuilder
├── Complex sequence/stagger → AnimationController + CurvedAnimation + AnimatedBuilder
├── Shared element (cross-screen) → Hero widget + unique tag
├── Page enter/exit → GoRouter CustomTransitionPage or pageBuilder
├── Spring/bounce/momentum → SpringSimulation, BouncingScrollPhysics
└── Vector/sprite → Rive or Lottie package
GPU に適したプロパティ: transform、opacity → スムーズ
CPU 負荷の高いプロパティ: width、height、margin、padding → カクつき
📊 状態管理の自動検出
状態コードを書く前に、インポートを確認します。
| 見つかったインポート | 使用するもの |
|---|---|
flutter_riverpod | Riverpod のルール |
provider パッケージ | Provider のルール |
| どちらもなし | ユーザーに確認 → 新規プロジェクトには Riverpod を推奨 |
⚡ パフォーマンス早見表
class MyCard extends StatelessWidget {
const MyCard({super.key});
@override
Widget build(BuildContext context) => const Padding(
padding: EdgeInsets.all(16),
child: Text('Hello'),
);
}
RepaintBoundary(child: AnimatedWidget(...))
ListView.builder(itemCount: n, itemBuilder: (ctx, i) => Item(items[i]))
final name = ref.watch(userProvider.select((u) => u.name));
🧠 チェックポイント(Flutter の作業前に記入)
🧠 FLUTTER CHECKPOINT:
State: [ Riverpod / Provider / BLoC / Vanilla ]
Navigation: [ GoRouter / auto_route / Navigator 1.0 ]
Design: [ Material 3 / Cupertino / Custom ]
Platforms: [ Mobile / Tablet / Desktop / Web ]
Files Read: [ List files read ]
3 Rules I Will Apply:
1. _______________
2. _______________
3. _______________
Anti-Patterns I Will Avoid:
1. _______________
2. _______________
🔴 チェックポイントを記入できない場合 → スキルファイルを読んでください。
📋 チェックリスト
画面ごと
- Riverpod の場合は
ConsumerWidgetを使用しているか?コンストラクターはconstか? - タッチ領域は 48dp 以上か?
- 読み込み状態とエラー状態を定義しているか?
- 戻るナビゲーションをテストしたか(PopScope または GoRouter の canPop)?
- 色やフォントサイズをハードコードしていないか?
アニメーションごと
-
width/heightではなく、transform/opacityをアニメーションさせているか? -
AnimationController.dispose()を呼び出しているか? - イージングカーブを使用し、時間は 150ms 以上か?
- 複雑なペインターに
RepaintBoundaryを設定しているか?
リリース前
- 監査スクリプトを実行し、🔴 の指摘をすべて修正する
-
flutter analyzeを実行し、const の不足に関する警告がないことを確認する - Android の戻るボタンをテストし、画面が戻れなくならないことを確認する
- ダークモードをテストし、すべての色が Theme から取得されていることを確認する
- タブレットのレイアウトをテストし、オーバーフローがないことを確認する
- すべての
.when()でエラー状態を処理する
📚 参考ファイル
| ファイル | 使用する場面 |
|---|---|
| flutter-design-thinking.md | 最初に読む — AI の既定動作を防ぐ |
| flutter-state-ui.md | Riverpod と Provider のルール、パターン、移行 |
| flutter-navigation.md | GoRouter、戻る動作、ディープリンク、タブ |
| flutter-animations.md | 暗黙的・明示的アニメーション、Hero、トランジション、物理挙動 |
| flutter-theme-system.md | Material 3、ColorScheme、TextTheme |
| flutter-layout-system.md | レスポンシブ、LayoutBuilder、Slivers |
| flutter-performance.md | const、RepaintBoundary、DevTools |
| flutter-custom-paint.md | Canvas、CustomPainter、ピクセル単位の精度 |
ピクセル単位の精度とは、すべての余白、色、書体の選択に意図があり、テーマに基づいていることです。マジックナンバーではなく、デザインシステムを通じてピクセルを管理してください。
コメント
Markdown 対応