flutter-add-widget-preview について
Flutter Widget Previewer でウィジェットを単独表示し、サイズやテーマなどを設定するためのスキルです。アノテーション、カスタムプレビュー、Web 実行環境の制約を扱います。
主な機能
- 01@Preview によるウィジェット指定
- 02サイズ・テーマ・ローカライズ設定
- 03カスタム・複数構成プレビュー
- 04Web プレビューの制約への対応
活用シーン
- 01アプリ全体から切り離して確認
- 02テーマや文字サイズの比較
- 03複数ウィジェットで設定を再利用
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ flutter/ agent-plugins --skill flutter-add-widget-previewインストール後、Claude Code で/flutter-add-widget-previewを入力して読み込まれたか確認します。
詳細
Flutter ウィジェットのプレビュー
目次
プレビューのガイドライン
Flutter Widget Previewer を使用すると、アプリケーション全体のコンテキストから切り離して、ウィジェットをリアルタイムでレンダリングできます。
- 対象要素:
@Previewアノテーションは、トップレベル関数、クラス内の静的メソッド、または必須引数がなく、WidgetまたはWidgetBuilderを返すパブリックなウィジェットのコンストラクター/ファクトリーに適用します。 - インポート: プレビュー用アノテーションを使用するには、必ず
package:flutter/widget_previews.dartをインポートします。 - カスタムアノテーション:
Previewクラスを拡張して、複数のウィジェットに共通のプロパティ(カスタムテーマ、ラッパー、サイズなど)を適用するカスタムアノテーションを作成します。 - 複数の構成: 1 つの対象に複数の
@Previewアノテーションを適用すると、プレビューインスタンスを複数生成できます。または、MultiPreviewを拡張して、共通の複数プレビュー構成をカプセル化できます。 - 実行時の変換: カスタムの
PreviewクラスまたはMultiPreviewクラスでtransform()メソッドをオーバーライドすると、実行時にプレビュー構成を動的に変更できます(たとえば、constコンストラクターでは不可能な、パラメーターに基づいた動的な名前の生成など)。
プレビューのパラメーター
@Preview アノテーションでは、プレビュー環境を調整するために次のパラメーターを指定できます。
name:プレビューインスタンスを説明する名前です。group:プレビューアー内で関連するプレビューをグループ化するための名前です。size:Sizeオブジェクトを使用して指定する人工的な制約です。textScaleFactor:カスタムのフォントスケール係数です。wrapper:プレビュー対象のウィジェットを特定のウィジェットツリーでラップする関数です(状態や継承ウィジェットの注入など)。theme:PreviewThemeDataのサブクラスのインスタンスを返す関数です。テーマを順番に重ねる機能を使って、カスタムのテーマを提供します。brightness:初期テーマのBrightnessです(Brightness.lightまたはBrightness.dark)。localizations:ローカライズ設定を適用する関数です。
制限事項への対応
Widget Previewer はウェブ環境で実行されるため、プレビュー可能なウィジェットを作成する際は次の制約を守ってください。
- ネイティブ API: ネイティブプラグインや
dart:io、dart:ffiの API は使用しないでください。dart:ioまたはdart:ffiに推移的に依存するウィジェットは、呼び出し時に例外をスローします。条件付きインポートまたはラッパーを使用して、プレビューモードではこれらをモックするか回避してください。 - アセットパス:
dart:uiのfromAssetAPI で読み込むアセットには、パッケージベースのパスを使用してください(例:assets/my_image.pngではなくpackages/my_package_name/assets/my_image.png)。 - パブリックなコールバック: コード生成の要件を満たすため、プレビューアノテーションに渡すすべてのコールバック引数がパブリックで定数であることを確認してください。
- 制約: ウィジェットに制約がない場合は、
@Previewアノテーションのsizeパラメーターを使って明示的な制約を適用してください。制約のないウィジェットは、デフォルトでビューポートのおよそ半分のサイズになります。 - ビルドキャッシュ: プレビューアーは、プロジェクトルートにある
.widget_preview/フォルダーにビルドをキャッシュします。
ワークフロー
ウィジェットプレビューの作成
新しいウィジェットプレビューを実装するときは、このチェックリストをコピーして進捗を記録してください。
-
package:flutter/widget_previews.dartをインポートします。 - 有効な対象(トップレベル関数、静的メソッド、またはパラメーターのないパブリックコンストラクター)を特定します。
- 対象に
@Previewアノテーションを適用します。 - 必要に応じてプレビューのパラメーター(
name、group、size、textScaleFactor、wrapper、theme、brightness、localizations)を設定します。 - 複数のウィジェットに同じ構成を適用する場合は、その構成を
PreviewまたはMultiPreviewを拡張したカスタムクラスに切り出します。
プレビューの操作
Widget Previewer を起動して操作するには、適切な条件分岐ワークフローに従います。
サポート対象の IDE(Android Studio、IntelliJ、Flutter 3.47+ を使用した VS Code)を使用する場合:
- IDE を起動します。Widget Previewer が自動的に起動します。
- サイドバーの「Flutter Widget Preview」タブを開きます。
- 現在アクティブなファイル以外のプレビューを表示する場合は、左下にある「Filter previews by selected file」を切り替えます。
コマンドラインを使用する場合:
- Flutter プロジェクトのルートディレクトリに移動します。
flutter widget-preview startを実行します。- 自動的に開く Chrome 環境を確認します。
フィードバックループ:プレビューの反復
- ウィジェットのコードまたはプレビュー設定を変更します。
- Widget Previewer で自動更新を確認します。
- グローバル状態(静的初期化子など)を変更した場合:右下にあるグローバルなホットリスタートボタンをクリックします。
- ローカルウィジェットの状態のみをリセットする場合:対象のプレビューカードにある個別のホットリスタートボタンをクリックします。
- IDE/CLI コンソールでエラーを確認し、修正して、繰り返します。
例
基本的なプレビュー
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';
@Preview(name: 'Submit Button', group: 'Form Controls')
Widget submitButtonPreview() => const ElevatedButton(
onPressed: null,
child: Text('Submit'),
);
PreviewThemeData と変換を使用したカスタムプレビュー
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';
final class ThemedPreview extends Preview {
const ThemedPreview({
super.name,
super.group,
super.brightness,
});
PreviewThemeData _themeBuilder() =>
CustomThemeData(brightness: brightness);
@override
Preview transform() {
final originalPreview = super.transform();
final themeVariant = switch (brightness) {
null => 'Responsive',
final b => b.name,
};
final builder = originalPreview.toBuilder();
final baseName = originalPreview.name ?? 'Preview';
builder
..name = '$baseName [$themeVariant]'
..theme = _themeBuilder;
return builder.build();
}
}
final class CustomThemeData extends PreviewThemeData {
const CustomThemeData({this.brightness});
final Brightness? brightness;
@override
Widget apply(BuildContext context, Widget child) {
return Theme(
data: ThemeData.from(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.teal,
brightness: brightness ??
MediaQuery.maybePlatformBrightnessOf(context) ??
Brightness.light,
),
),
child: child,
);
}
}
@ThemedPreview(name: 'Themed Action Button', brightness: Brightness.dark)
Widget themedButtonPreview() => const ElevatedButton(
onPressed: null,
child: Text('Action'),
);
MultiPreview の実装
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';
/// Creates light and dark mode previews automatically.
final class MultiBrightnessPreview extends MultiPreview {
const MultiBrightnessPreview({required this.name});
final String name;
@override
List<Preview> get previews => const [
Preview(brightness: Brightness.light),
Preview(brightness: Brightness.dark),
];
@override
List<Preview> transform() {
final previews = super.transform();
return previews.map((preview) {
final builder = preview.toBuilder()
..group = 'Brightness'
..name = '$name - ${preview.brightness!.name}';
return builder.toPreview();
}).toList();
}
}
@MultiBrightnessPreview(name: 'Primary Card')
Widget cardPreview() => const Card(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text('Content'),
),
);
コメント
Markdown 対応