flutter-native-ui について
flutter-native-ui は、現行の Flutter と Dart のドキュメントに基づいて UI を構築・確認するスキルです。既存のデザインシステムを維持しながら、適切なウィジェットやレイアウトを選べます。
主な機能
- 01公式ドキュメントに基づく UI 設計
- 02既存テーマとナビゲーションの維持
- 03Material と Cupertino のパターン案内
- 04レスポンシブなレイアウトとコントロール
- 05アナライザーと表示の検証
活用シーン
- 01既存 Flutter アプリへの画面追加
- 02アダプティブな操作部品とナビの選択
- 03空・読み込み・エラー状態の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ thesimpleapp/ flutter-app-skills --skill flutter-native-uiインストール後、Claude Code で/flutter-native-uiを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/animations.mdcontrols.mdicons-and-media.mdlayout.mdnavigation.mdstorage.mdtheming.mdvisual-effects.md詳細
Flutter ネイティブ UI
UI の選択はすべて、React Native や Expo のパターンではなく、最新の Flutter と Dart のドキュメントに基づいてください。flutter --version を確認してください。公式情報源:docs.flutter.dev、api.flutter.dev、dart.dev、m3.material.io、および flutter.dev の pub.dev パッケージ。
プロジェクトにすでにデザインシステム、トークン、またはルーターがある場合は、それを拡張してください。2つ目のテーマやナビゲーターを独自に作らないでください。
ウィジェットが独自の ThemeExtension、ブランドトークンのファイル、または Material のインク効果ではなく *Pressable を使っている場合は、そこで作業を止めて flutter-custom-design-system に従ってください。そのアプリを標準の Material 3 に合わせて「修正」しないでください。
参照資料
必要なファイルだけを読んでください。
references/
navigation.md go_router, tabs, sheets, dialogs, transitions
theming.md ColorScheme, TextTheme, light/dark, Cupertino
layout.md SafeArea, MediaQuery.*Of, breakpoints, slivers
controls.md Adaptive constructors, buttons, fields, pickers
animations.md Implicit first, Hero, M3 motion, lists
icons-and-media.md Icons.adaptive, images, camera, audio, video
visual-effects.md Elevation, blur, gradients
storage.md Preferences, secure storage, files, SQL
デザインシステム
アプリの外枠は1つに決め、統一してください。
| 製品 | ルート | 外枠 |
|---|---|---|
| クロスプラットフォーム(デフォルト) | MaterialApp / MaterialApp.router | Material 3 + .adaptive() コントロール |
| iOS 優先 | CupertinoApp / CupertinoApp.router | Cupertino ウィジェット + HIG の間隔 |
| 既存アプリ | すでに使用しているもの | 方針を示すためにアプリ全体のスタイルを変更しないでください |
Flutter はOS の動作(スクロール物理特性、戻るジェスチャー、テキスト編集、触覚フィードバック)を自動的に適応させます。タブバー、アプリバー、情報アーキテクチャは自動で切り替わりません。これらは明示的に選択する必要があります。プラットフォームへの適応を参照してください。
.adaptive() コンストラクターと Icons.adaptive を除き、同じ画面内で Material と Cupertino のウィジェットを混在させないでください。
Material 3 は Flutter 3.16 以降のデフォルトです。useMaterial3: false は決して設定しないでください。オプトイン設定であるかのように useMaterial3: true を渡すことも避けてください。
インポート(Flutter 3.47 以降)
Material と Cupertino は、独立した 1.0 パッケージとして提供されています:material_ui と cupertino_ui。SDK のコピーも 3.47 では引き続き動作しますが、2026年秋の stable で非推奨になる予定です。
- 既存プロジェクト: ツリー内ですでに使われているインポート形式を維持してください。
- 新規の 3.47 以降のアプリ、または移行を依頼された場合:
flutter pub add material_ui
# only if you build Cupertino chrome:
flutter pub add cupertino_ui
dart fix --apply --code=migrate_design_widgets
これにより、package:flutter/material.dart → package:material_ui/material_ui.dart と、package:flutter/cupertino.dart → package:cupertino_ui/cupertino_ui.dart が書き換えられます。
pubspec.yaml が更新されない場合は、flutter pub add material_ui(および cupertino_ui)を実行してから、もう一度 dart fix --apply を実行してください。
SDK ライブラリを引き続きインポートしているレガシーパッケージのウィジェットには、ブリッジが必要です。
MaterialApp(
builder: (context, child) => MaterialUiCompatibilityBridge(child: child!),
)
ローカライズ:material_ui の GlobalMaterialLocalizations.delegates を localizationsDelegates に指定します(Cupertino と Widgets も含まれます)。移行後は flutter_localizations の GlobalMaterialLocalizations / GlobalCupertinoLocalizations を残さないでください。
画面の構築
- 既存のテーマ、ルーター、近くの画面を確認してください。それらの規約に合わせてください。
- 足場を選びます:
Scaffold+AppBar/SliverAppBar(Material)、またはCupertinoPageScaffold+CupertinoNavigationBar/CupertinoSliverNavigationBar(Cupertino)。 - ページタイトルはアプリバー/ナビゲーションバーに配置し、本文の先頭に独自の
Textを置かないでください。 - コンテンツは本文の周囲に
SafeAreaを使ってインセットしてください。Scaffold全体を囲まないでください(AppBarはすでにステータスバーの下まで描画されます)。入れ子のSafeAreaは重複分が折りたたまれるため、MediaQuery.paddingを自分で読み取ってパディングを追加しないでください。 - スクロール可能なページには
CustomScrollView+ スライバー、またはListView.builderを使います。フォームには、オーバーフローする装飾のないColumnではなく、ListView/CustomScrollViewを使ってください。 - 色と文字スタイルは
ColorScheme.of(context)とTextTheme.of(context)から取得してください。Colors.blueのような生の色や、個別に指定するfontSize: 13は使わないでください。 - インタラクティブなコントロールには
const ValueKey<String>('kebab-name')を設定してください。 - 編集後はホットリロードを行い、確認してください(「確認」を参照)。
厳守事項
テーマと色
ColorScheme.fromSeedで配色を構築します。theme+darkTheme+themeModeを組み合わせます。ColorScheme.of(context)とTextTheme.of(context)を使ってトークンを読み取ります(Theme.of(context).colorScheme/.textThemeと同じです)。- M3 のロールを使います:
primary/onPrimary、surface/onSurface、surfaceContainer*、outline、error。primarySwatchやaccentColorは使いません。 - Cupertino の色には
CupertinoColors/CupertinoDynamicColorを使い、CupertinoDynamicColor.resolve(color, context)で解決します。
レイアウト
MediaQuery.sizeOf/paddingOf/viewInsetsOf/viewPaddingOf/textScalerOf/platformBrightnessOf/highContrastOf/accessibleNavigationOfを使います。MediaQuery.of(context).sizeは使いません(MediaQuery が変更されるたびに再ビルドされます)。- 間隔には
Row/Column/Flexのspacingを使います。Wrapではspacing+runSpacingを使います。すべての子ウィジェットの間にSizedBoxを追加しないでください。 - デバイスの種類ではなく、ウィンドウサイズに基づいてレイアウトします。スマートフォンかタブレットかを判定するために
Platform.isIOSを使わないでください。アプリのルートでOrientationBuilderを使わないでください。ブレークポイント:compact<600、medium600–839、expanded≥840(M3 のウィンドウサイズクラス)。 - 画面の向きを固定しないでください。
flutter_screenutilやデザインピクセル用のスケーラーを使わないでください。
ウィジェット(新規コード)
| 使用するもの | 使用しないもの |
|---|---|
FilledButton、FilledButton.tonal、OutlinedButton、TextButton | 主要アクションとしての ElevatedButton、RaisedButton、FlatButton |
NavigationBar + NavigationDestination | BottomNavigationBar |
幅が広い場合の NavigationRail/NavigationDrawer | デスクトップで引き伸ばしたスマートフォン向けナビゲーションバー |
SegmentedButton | ToggleButtons |
DropdownMenu | DropdownButton/DropdownButtonFormField |
MenuAnchor/MenuBar | 新しいメニューでの PopupMenuButton |
SearchAnchor/SearchBar | アプリバーに自作の検索用 TextField を置くこと |
Card.filled/Card.outlined | 場当たり的な Container + BoxShadow のカード |
ListView.builder/スライバー | ListView(children: hugeList) |
Switch.adaptive、Slider.adaptive、Checkbox.adaptive、Radio.adaptive、CircularProgressIndicator.adaptive、RefreshIndicator.adaptive、AlertDialog.adaptive、showAdaptiveDialog | OS ネイティブの操作要素に対して、プラットフォームを考慮しない Material コントロール |
ナビゲーション
- 新しいマルチスクリーンアプリでは、
go_router+MaterialApp.router/CupertinoApp.routerを使います。公式ドキュメントでは、MaterialApp.routesによる名前付きルートは推奨されていません。 - 既存アプリで
Navigator.pushを使っている場合は、移行を依頼されない限りNavigatorを使い続けます。 - タブごとのスタックを維持する必要があるタブには、
StatefulShellRoute.indexedStackを使います。 - シートやダイアログはページレスのままにします(
showModalBottomSheet、showAdaptiveDialog)。ディープリンク可能である必要がない限り、すべてのポップアップを GoRoute にしないでください。 - 全画面モーダルには
fullscreenDialog: true(iOS の表示方式)を使うか、そのページフラグを設定したGoRouteを使います。
Dart/ウィジェット
constコンストラクターを使います。400 行のbuildをひとつ書くより、小さなウィジェットに分割します。- ファイル名は
snake_case.dart、型名はPascalCaseにします。インタラクティブなキーには kebab-case の文字列を使います。 - ユーザーがコピーできる値には
SelectableText、または祖先にSelectionAreaを使います。 - 表形式の数字には
fontFeatures: const [FontFeature.tabularFigures()]を使います。 - デバッグ専用のジャンプ用チップや入力済みフィールドは
kDebugModeの内側に置き、実際の認証フローを通すようにします。 - 画面を実装するために GetX、
flutter_screenutil、FontAwesome-for-chrome、新しい状態管理パッケージを追加しないでください。
Expo/RN の慣習を持ち込まない
StyleSheet、process.env.EXPO_OS、SafeAreaView、CSS のboxShadow、kebab-case のソースファイルは使わないでください。flex: 1のスタイルマップは使わず、Expanded/Flexibleを使います。expo-imageで SF Symbols を使わないでください。Icons.adaptive/CupertinoIconsを使います。
検証
UI の作業は、編集内容が適用された時点では完了ではありません。
- 変更したファイルでアナライザーの問題がないことを確認します(
dart analyze/flutter analyze)。 - 実行中のアプリをホットリロードします。
main、ルート、またはグローバルテーマを変更した場合は、ホットリスタートします。 - 実行中の画面を確認します(スクリーンショット、ウィジェットプレビュー、またはプロジェクトのビジュアルループ)。古い画面表示は証拠になりません。
- 分離したウィジェットには、
package:flutter/widget_previews.dartの@Previewを使用します(3.47 で安定版)。ウィジェットプレビューアーを参照してください。 - 変更した画面の空、読み込み中、エラー、キーボード表示中の状態を確認します。また、同じ状態を読み取る他のルートも確認します。