Flutter Widget 预览器
学习如何使用 Flutter Widget 预览器,在全应用之外实时查看 widget 渲染效果。
本指南将介绍如何使用 Flutter Widget 预览器。
概览
#借助 Flutter Widget 预览器,你可以在 Chrome 浏览器中在全应用之外实时查看 widget 渲染。要启动预览器、在其中展示 widget 并自定义预览,请参阅以下各节。
打开预览器
#IDEs
#IDE
#自 Flutter 3.38 起,Android Studio、Intellij 和 Visual Studio Code 在启动时会自动启动 Flutter Widget 预览器。
Android Studio 与 Intellij
#在 Android Studio 或 Intellij 中打开 Widget 预览器:在侧边栏打开 "Flutter Widget Preview" 标签页:
Visual Studio Code
#Visual Studio Code
#在 Visual Studio Code 中打开 Widget 预览器:在侧边栏打开 "Flutter Widget Preview" 标签页:
命令行
#要启动 Flutter Widget 预览器,请进入 Flutter 项目根目录,在终端运行以下命令。这会启动本地服务器,并在 Chrome 中打开会根据项目变更自动更新的 Widget Preview 环境。
flutter widget-preview start
预览 widget
#
启动预览器后,要查看 widget,必须使用
package:flutter/widget_previews.dart 中定义的 @Preview
注解。该注解可应用于:
-
Top-level functions that return a
WidgetorWidgetBuilder. -
Static methods within a class that return a
WidgetorWidgetBuilder. -
Public Widget constructors and factories with no required arguments.
返回
Widget或WidgetBuilder的 顶层函数。返回
Widget或WidgetBuilder的类内 静态方法。无必需参数的 公共 Widget 构造函数和工厂。
以下是使用 @Preview 注解预览 Text widget 的基本示例:
import 'package:flutter/widget_previews.dart';
import 'package:flutter/material.dart'; // For Material widgets
@Preview(name: 'My Sample Text')
Widget mySampleText() {
return const Text('Hello, World!');
}
每个预览实例提供多种控件,用于与预览中的 widget 交互。从左到右:
Zoom in: Magnifies the widget in the preview.
放大: 放大预览中的 widget。
-
Zoom out: Reduces the magnification of the widget in the preview.
缩小: 减小预览中的放大倍数。
-
Reset zoom: Returns the widget preview to its default zoom level.
重置缩放: 将 widget 预览恢复为默认缩放级别。
-
Toggle between light and dark mode: Switches the preview's theme between a light and dark color scheme.
切换浅色/深色模式: 在浅色与深色配色方案之间切换预览主题。
-
Perform a hot restart for the individual preview: Restarts only the specific widget preview, allowing changes to be applied quickly without restarting the entire application.
-
对单个预览执行热重启: 仅重启该 widget 预览,可快速应用更改而无需重启整个应用。
若已修改全局状态(例如静态初始化器已更改),可使用环境右下角的按钮让整个 widget 预览器热重启。
按所选文件筛选预览
#在 IDE 中查看预览时,widget 预览器会按当前所选文件筛选预览集:
要禁用此行为,请切换环境左下角的 "Filter previews by selected file"(按所选文件筛选预览)选项。
自定义预览
#
@Preview
注解提供多个参数,可用于自定义预览:
name: A descriptive name for the preview.name:预览的描述性名称。-
group: A name used to group related previews together in the widget previewer. group:在 widget 预览器中将相关预览分组在一起的名称。-
size: Artificial size constraints using aSizeobject. size:使用Size对象施加的人工尺寸约束。textScaleFactor: A custom font scale.textScaleFactor:自定义字体缩放。-
wrapper: A function that wraps your previewed widget in a specific widget tree (for example, to inject application state into the widget tree with anInheritedWidget). -
wrapper:将预览 widget 包裹在特定 widget 树中的函数(例如通过InheritedWidget向 widget 树注入应用状态)。 -
theme: A function to provide Material and Cupertino theming data. theme:提供 Material 与 Cupertino 主题数据的函数。brightness: The initial theme brightness.brightness:初始主题亮度。-
localizations: A function to apply a localization configuration. localizations:应用本地化配置的函数。
创建自定义预览注解
#
为减少使用一组通用属性定义预览所需的样板代码,可扩展 Preview
注解类,为项目创建定制的自定义预览注解。
以下示例提供主题数据的自定义预览注解:
final class MyCustomPreview extends Preview {
const MyCustomPreview({
super.name,
super.group,
super.size,
super.textScaleFactor,
super.wrapper,
super.brightness,
super.localizations,
}) : super(theme: MyCustomPreview.themeBuilder);
static PreviewThemeData themeBuilder() {
return PreviewThemeData(
materialLight: ThemeData.light(),
materialDark: ThemeData.dark(),
);
}
}
扩展 Preview
注解类还可重写 Preview.transform()
方法。
widget 预览器会调用此方法,在运行时修改预览,从而实现 const 上下文中无法实现的预览配置:
final class TransformativePreview extends Preview {
const TransformativePreview({
super.name,
super.group,
super.size,
super.textScaleFactor,
super.wrapper,
super.brightness,
super.localizations,
});
// Note: this is no longer public or static as it's injected
// at runtime when transform() is invoked.
PreviewThemeData _themeBuilder() {
return PreviewThemeData(
materialLight: ThemeData.light(),
materialDark: ThemeData.dark(),
);
}
@override
Preview transform() {
final originalPreview = super.transform();
// Create's a PreviewBuilder that can be used to modify
// the preview contents.
final builder = originalPreview.toBuilder();
builder
..name = 'Transformed - ${originalPreview.name}'
..theme = _themeBuilder;
// Return the updated Preview instance.
return builder.toPreview();
}
}
创建多种预览配置
#
为同一函数或构造函数应用多个 @Preview
注解,即可轻松创建多种不同配置的预览:
@Preview(
group: 'Brightness',
name: 'Example - light',
brightness: Brightness.light,
)
@Preview(
group: 'Brightness',
name: 'Example - dark',
brightness: Brightness.dark,
)
Widget buttonPreview() => const ButtonShowcase();
要简化使用通用配置创建多个预览,可扩展 MultiPreview
创建会生成多个预览的自定义注解。以下 MultiPreview
会创建与上一示例相同的两项预览:
/// Creates light and dark mode previews.
final class MultiBrightnessPreview extends MultiPreview {
const MultiBrightnessPreview();
@override
List<Preview> get previews => const [
Preview(
group: 'Brightness',
name: 'Example - light',
brightness: Brightness.light,
),
Preview(
group: 'Brightness',
name: 'Example - dark',
brightness: Brightness.dark,
),
];
}
@MultiBrightnessPreview()
Widget buttonPreview() => const ButtonShowcase();
与 Preview
类似,MultiPreview
也提供 MultiPreview.transform()
方法,在运行时对每个预览进行变换:
/// Creates light and dark mode previews.
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'
// Building names based on values provided to the annotation
// isn't possible within a constant constructor. However,
// there's no such restriction when building a Preview at
// runtime.
..name = '$name - ${preview.brightness!.name}';
return builder.toPreview();
}).toList();
}
}
@MultiBrightnessPreview(name: 'Example')
Widget buttonPreview() => const ButtonShowcase();
限制与约束
#使用 Flutter Widget 预览器时应注意以下限制:
-
Public callback names: All callback arguments provided to preview annotations must be public and constant. This is required for the previewer's code generation implementation to work correctly.
-
公共回调名称:提供给预览注解的所有回调参数必须是 public 且为 constant。预览器的代码生成实现需要如此才能正常工作。
-
Unsupported APIs: Native plugins and any APIs from the
dart:ioordart:ffilibraries are not supported. This is because the widget previewer is built with Flutter Web, which doesn't have access to the underlying native platform APIs. While web plugins might work when using Chrome, there is no guarantee that they will work within other environments, such as when embedded in IDEs.Widgets with transitive dependencies on
dart:ioordart:ffiwill load correctly, but all APIs from these libraries will throw an exception when invoked.See the Dart documentation on conditional imports for details on how to structure your application to cleanly support platform-specific libraries when targeting multiple platforms.
-
不支持的 API:不支持原生插件以及
dart:io或dart:ffi库中的任何 API。因为 widget 预览器基于 Flutter Web 构建,无法访问底层原生平台 API。在 Chrome 中 Web 插件可能可用,但不保证在其他环境(例如嵌入 IDE 时)也能工作。对
dart:io或dart:ffi有传递依赖的 widget 可以正常加载,但调用这些库中的 API 时会抛出异常。有关如何在面向多平台时整洁地支持平台特定库,请参阅 Dart documentation on conditional imports(Dart 条件导入文档)。
-
Asset paths: When using
fromAssetAPIs fromdart:uito load resources, you must use package-based paths instead of direct local paths. This ensures that the assets can be correctly located and loaded within the previewer's web environment. For example, use'packages/my_package_name/assets/my_image.png'instead of'assets/my_image.png'. -
资源路径:使用
dart:ui的fromAssetAPI 加载资源时,必须使用 基于 package 的路径,而非直接本地路径。这样资源才能在预览器的 Web 环境中正确定位和加载。例如使用'packages/my_package_name/assets/my_image.png',而不是'assets/my_image.png'。 -
Unconstrained widgets: Unconstrained widgets are automatically constrained to approximately half the height and width of the widget previewer. This behavior is likely to change in the future, so constraints should be applied using the
sizeparameter when possible. -
无约束 widget:无约束 widget 会自动约束为约为 widget 预览器高度和宽度的一半。此行为未来可能变更,因此尽可能使用
size参数施加约束。 -
Multi-project support in IDEs: The widget previewer currently only supports displaying previews contained within a single project or Pub workspace. We're actively investigating options to support IDE sessions with multiple Flutter projects (#173550).
-
IDE 中的多项目支持:widget 预览器目前仅支持显示单个项目或 Pub 工作区内的预览。我们正在积极研究支持包含多个 Flutter 项目的 IDE 会话的方案 (#173550)。
除非另有说明,本文档之所提及适用于 Flutter 3.44.0 版本。本页面最后更新时间:2026-06-04。查看文档源码 或者 为本页面内容提出建议。