SKILL.md
只读
名称
flutter-add-widget-preview
描述
使用 previews.dart 系统为项目添加交互式 widget 预览。在创建新的 UI 组件或更新现有屏幕时使用,以确保一致的设计和交互式测试。
预览 Flutter Widget
目录
预览指南
使用 Flutter Widget 预览器实时渲染 widget,与完整的应用程序上下文隔离。
- 目标元素: 将
@Preview注解应用于顶级函数、类中的静态方法,或没有必需参数且返回Widget或WidgetBuilder的公共 widget 构造函数/工厂。 - 导入: 始终导入
package:flutter/widget_previews.dart以访问预览注解。 - 自定义注解: 扩展
Preview类以创建自定义注解,为多个 widget 注入公共属性(例如主题、包装器)。 - 多个配置: 对单个目标应用多个
@Preview注解以生成多个预览实例。或者,扩展MultiPreview以封装常见的多预览配置。 - 运行时转换: 在自定义
Preview或MultiPreview类中重写transform()方法,以在运行时动态修改预览配置(例如,基于动态值生成名称,这在const上下文中是不可能的)。
处理限制
在编写可预览的 widget 时,请遵守以下约束,因为 Widget 预览器在 Web 环境中运行:
- 无原生 API: 不要使用来自
dart:io或dart:ffi的原生插件或 API。具有对dart:io或dart:ffi传递依赖的 widget 在调用时会抛出异常。使用条件导入在预览模式下模拟或绕过这些依赖。 - 资源路径: 对于通过
dart:ui的fromAssetAPI 加载的资源,使用基于包的路径(例如packages/my_package_name/assets/my_image.png而不是assets/my_image.png)。 - 公共回调: 确保提供给预览注解的所有回调参数都是公共且常量的,以满足代码生成要求。
- 约束: 如果您的 widget 是无约束的,请使用
@Preview注解中的size参数应用显式约束,因为预览器默认将它们约束为大约视口的一半。
工作流程
创建 Widget 预览
在实现新的 widget 预览时,复制并跟踪此检查清单:
- [ ] 导入
package:flutter/widget_previews.dart。 - [ ] 确定一个有效的目标(顶级函数、静态方法或无参数的公共构造函数)。
- [ ] 将
@Preview注解应用于目标。 - [ ] 根据需要配置预览参数(
name、group、size、theme、brightness等)。 - [ ] 如果要将相同的配置应用于多个 widget,请将配置提取到扩展
Preview的自定义类中。
与预览交互
按照适当的条件工作流程启动并与 Widget 预览器交互:
如果使用支持的 IDE(Android Studio、IntelliJ、VS Code 与 Flutter 3.38+):
- 启动 IDE。Widget 预览器会自动启动。
- 在侧边栏中打开“Flutter Widget Preview”选项卡。
- 如果您想查看当前活动文件之外的预览,请切换左下角的“Filter previews by selected file”。
如果使用命令行:
- 导航到 Flutter 项目的根目录。
- 运行
flutter widget-preview start。 - 查看自动打开的 Chrome 环境。
反馈循环:预览迭代
- 修改 widget 代码或预览配置。
- 观察 Widget 预览器中的自动更新。
- 如果修改了全局状态(例如静态初始化器):单击右下角的全局热重启按钮。
- 如果只需要重置本地 widget 状态:单击特定预览卡片上的单个热重启按钮。
- 检查 IDE/CLI 控制台中的错误 -> 修复 -> 重复。
示例
基本预览
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';
@Preview(name: 'My Sample Text', group: 'Typography')
Widget mySampleText() {
return const Text('Hello, World!');
}
带运行时转换的自定义预览
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';
final class TransformativePreview extends Preview {
const TransformativePreview({
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();
builder
..name = 'Transformed - ${originalPreview.name}'
..theme = _themeBuilder;
return builder.toPreview();
}
}
@TransformativePreview(name: 'Custom Themed Button')
Widget myButton() => const ElevatedButton(onPressed: null, child: Text('Click'));
MultiPreview 实现
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart';
/// 自动创建亮色和暗色模式预览。
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')));






