mcpField
F
flutter-add-widget-preview

flutter-add-widget-preview

github.com/dhruvanbhalara开发3050 次安装9 周前更新
代码仓库

关于 flutter-add-widget-preview

这项技能指导 Flutter 开发者使用 Widget Previewer 添加和迭代组件预览,涵盖注解、尺寸约束、可复用配置及 IDE 或命令行反馈流程。

主要功能

  1. 01为支持的组件目标添加 @Preview
  2. 02设置预览名称、分组和尺寸
  3. 03创建可复用的 Preview 与 MultiPreview 类型
  4. 04通过 IDE 或命令行迭代实时预览
  5. 05处理 Web 预览环境的限制

适用场景

  1. 01脱离完整应用上下文预览组件
  2. 02展示组件的浅色和深色变体
  3. 03为无约束组件设置预览尺寸
  4. 04在多个组件间复用预览配置

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dhruvanbhalara/skills --skill flutter-add-widget-preview

安装后在 Claude Code 中输入/flutter-add-widget-preview确认已加载。

详细介绍

目录

预览指南

使用 Flutter Widget Previewer 实时渲染 Widget,使其脱离完整的应用上下文独立运行。

  • 目标元素:将 @Preview 注解用于:
    • 返回 Widget 的顶层函数
    • 类中返回 Widget 的静态方法
    • 不需要必需参数的公开 Widget 构造函数或工厂
  • 导入:始终导入 package:flutter/widget_previews.dart。
  • 多个配置:对单个目标应用多个 @Preview 注解,以创建多个预览实例(例如,浅色/深色模式)。
  • 命名:使用 name 和 group 参数整理预览面板。
  • 尺寸:如果 Widget 没有约束,则使用 size 参数显式设置约束(预览器默认使用约半个视口)。

处理限制

Widget Previewer 在网页环境中运行。请遵守以下限制:

限制影响解决方法
不支持 dart:io文件系统和套接字不可用使用条件导入进行模拟
不支持 dart:ffi原生代码无法执行在预览模式下替换原生调用
资源路径dart:ui 的 fromAsset 需要使用包路径使用 packages/my_package/assets/...
回调必须公开且为常量注解参数中不能使用闭包
无约束的 Widget可能无法正确渲染在 @Preview 中设置 size 参数

IDE 和命令行集成

IDE(Android Studio、IntelliJ、VS Code,Flutter 3.38+)
  1. 启动 IDE。Widget Previewer 会自动启动。
  2. 在侧边栏中打开 “Flutter Widget Preview” 标签页。
  3. 点击左下角的 “Filter previews by selected file”,即可查看当前文件以外的预览。
命令行
flutter widget-preview start

打开带有实时预览的 Chrome 环境。

反馈循环
  1. 修改 Widget 代码或预览配置。
  2. 在 Widget Previewer 中查看自动更新。
  3. 如果修改了全局状态 → 点击全局热重启(右下角)。
  4. 如果只需重置局部 Widget 状态 → 点击预览卡片上的单独热重启按钮。
  5. 在 IDE/命令行控制台中检查错误 → 修复 → 重复以上步骤。

自定义注解

扩展预览

通过扩展 Preview 类,创建可复用的预览配置:

import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';

final class ThemedPreview extends Preview {
  const ThemedPreview({super.name, super.group});

  PreviewThemeData _themeBuilder() {
    return PreviewThemeData(
      materialLight: ThemeData.light(),
      materialDark: ThemeData.dark(),
    );
  }

  @override
  Preview transform() {
    final originalPreview = super.transform();
    final builder = originalPreview.toBuilder()
      ..name = 'Themed - ${originalPreview.name}'
      ..theme = _themeBuilder;
    return builder.toPreview();
  }
}

@ThemedPreview(name: 'Primary Button')
Widget primaryButton() => const ElevatedButton(onPressed: null, child: Text('Click'));
亮度变体的 MultiPreview
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() {
    return super.transform().map((preview) {
      final builder = preview.toBuilder()
        ..group = 'Brightness'
        ..name = '$name - ${preview.brightness!.name}';
      return builder.toPreview();
    }).toList();
  }
}

@MultiBrightnessPreview(name: 'User Card')
Widget userCard() => const Card(
  child: Padding(padding: EdgeInsets.all(16), child: Text('John Doe')),
);

工作流:添加 Widget 预览

任务进度
  • 步骤 1:导入 package:flutter/widget_previews.dart。
  • 步骤 2:确定有效目标(顶层函数、静态方法或无参构造函数)。
  • 步骤 3:应用带有 name、group、size 参数的 @Preview 注解。
  • 步骤 4:如果多个 Widget 复用相同配置 → 提取为自定义 Preview 子类。
  • 步骤 5:启动预览器(IDE 标签页或 flutter widget-preview start)。
  • 步骤 6:迭代:修改 Widget → 查看自动更新 → 修复错误 → 重复以上步骤。

示例

基本预览
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';

@Preview(name: 'Greeting Text', group: 'Typography')
Widget greetingText() {
  return const Text('Hello, World!', style: TextStyle(fontSize: 24));
}
带尺寸约束的预览
@Preview(
  name: 'Login Form',
  group: 'Forms',
  size: Size(400, 600),
)
Widget loginFormPreview() {
  return const MaterialApp(home: LoginForm());
}
在构造函数上添加预览
@Preview(name: 'Default Avatar')
class UserAvatar extends StatelessWidget {
  const UserAvatar({super.key});

  @override
  Widget build(BuildContext context) {
    return const CircleAvatar(radius: 40, child: Icon(Icons.person));
  }
}

评论

支持 Markdown