关于 ui-package
面向 Flutter 开发者的可复用 UI 包构建指南,围绕 Material 组件、ThemeExtension 主题令牌和一致的组件 API 组织设计。还规定包结构、公共导出、组件测试及 Widgetbook 目录等实践。
主要功能
- 01基于 Material 组件组合 UI
- 02使用 ThemeExtension 扩展主题令牌
- 03通过单一 barrel 文件导出公共 API
- 04每个组件配套行为测试
- 05包含 pumpApp 与 Widgetbook 脚手架
适用场景
- 01创建可复用的 Flutter UI 包
- 02为应用定义间距和自定义颜色令牌
- 03实现遵循 Material 的共享组件
- 04为组件编写交互测试并整理目录
MCP 相关
指南要求使用 Very Good CLI MCP 的 `create` 工具,并将 `subcommand` 设为 `app_ui_package` 来生成 UI 包。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ verygoodopensource/ vgv-ai-flutter-plugin --skill ui-package安装后在 Claude Code 中输入/ui-package确认已加载。
附带文件agents/openai.yamlreference.md
详细介绍
UI 包
创建 Flutter UI 包的最佳实践——一个可复用的 widget 库,构建于 package:flutter/material.dart 之上,通过特定于应用的组件、使用 ThemeExtension 定义的自定义设计令牌,以及一致的 API 表面来扩展它。
主题基础: 本技能侧重于 UI 包结构、widget API 和测试。有关 Material 3 主题的基础知识(
ColorScheme、TextTheme、组件主题、间距常量、浅色/深色模式),请参阅 Material Theming 技能(/material-theming)。这两项技能互为补充——Material Theming 介绍如何设置和使用ThemeData;本技能介绍如何使用ThemeExtension扩展它,并围绕它封装可复用的 widget。
核心标准
所有 UI 包工作都应遵循以下标准:
- 从
app_ui_package模板搭建——使用 Very Good CLI MCP 工具创建包,subcommand: 'app_ui_package'。绝不要使用flutter_package、dart_package或flutter create --template=package;它们生成的是精简包,不包含下文所述的主题、导出文件、测试辅助工具或 Widgetbook 脚手架 - 基于 Material 构建——依赖
flutter/material.dart并组合使用 Material widget;不要重新构建 Material 已提供的基础组件 - 每个文件对应一个 widget——每个公开 widget 都放在单独的文件中,文件名使用该 widget 名称的 snake_case 形式(例如,
app_button.dart) - 通过导出文件公开 API——通过单一导出文件(例如,
lib/my_ui.dart)公开所有公开 widget 和主题类;该文件还应重新导出material.dart,这样使用方只需一次导入,就能同时使用 Material 的 widget 和包自身的 widget,无需再导入 Material lib/src/是私有目录——使用方只导入导出文件,不导入其他文件;逐个导入文件(例如package:my_ui/src/widgets/app_button.dart)会访问私有实现,并且任何内部重命名都会导致导入失效。Tree shaking 会自动移除未使用的 widget,因此导出文件不会带来任何开销- 使用
ThemeExtension扩展主题——以 Material 的ThemeData、ColorScheme和TextTheme为基础(参见 Material Theming 技能);通过ThemeExtension<T>添加特定于应用的令牌(间距、自定义颜色),将每个令牌都注册到ThemeData.extensions中,并通过BuildContext扩展读取它们(context.appColors、context.appSpacing) - 每个 widget 都有对应的 widget 测试——行为测试需验证交互、回调和状态变化,并通过包的
pumpApp辅助工具进行泵测,而不是内联使用MaterialApp - 用可运行的代码纠正反模式——当请求涉及反模式表中的内容时,说明其错误之处,并在同一回复中提供修正后的实现。不要只提出异议,也不要询问是否可以按文档所述的方式实现
- 为所有公开类添加前缀——使用一致的前缀(例如
App、Vg),避免与 Material widget 发生命名冲突 - 尽可能在所有地方使用
const构造函数——所有 widget 构造函数都应在可行时声明为const - 为每个公开成员编写文档——每个公开类、构造函数参数和方法都必须有 dartdoc 注释
包结构
my_ui/
├── lib/
│ ├── my_ui.dart # Barrel file — re-exports material.dart + all public API
│ └── src/
│ ├── theme/
│ │ ├── app_theme.dart # AppTheme class with light/dark ThemeData builders
│ │ ├── app_colors.dart # AppColors ThemeExtension for custom color tokens
│ │ ├── app_spacing.dart # AppSpacing ThemeExtension for spacing tokens
│ │ └── app_text_styles.dart # Optional: extra text styles beyond Material's TextTheme
│ ├── widgets/
│ │ ├── app_button.dart
│ │ ├── app_text_field.dart
│ │ ├── app_card.dart
│ │ └── ...
│ └── extensions/
│ └── build_context_extensions.dart # context.appColors, context.appSpacing shortcuts
├── test/
│ ├── src/
│ │ ├── theme/
│ │ │ └── app_theme_test.dart
│ │ └── widgets/
│ │ ├── app_button_test.dart
│ │ └── ...
│ └── helpers/
│ └── pump_app.dart # Test helper wrapping widgets in MaterialApp + theme
├── widgetbook/ # Widgetbook catalog submodule (sandbox + showcase)
│ └── ...
└── pubspec.yaml
构建 Widget
Widget API 指南
- 组合使用 Material widget——将
FilledButton、OutlinedButton、TextField、Card等用作构建模块 - 只接受必需的最少参数——避免“厨房水槽式”构造函数
- 除
key和child/children外,所有参数都使用命名参数 - 未提供参数时,根据主题提供合理的默认值
- 使用
ValueChanged<T>或VoidCallback暴露回调——不要使用原始Function - 使用
Widget?实现可选的插槽式组合(前置、后置图标等)
反模式
| 反模式 | 正确做法 |
|---|---|
重建 Material 已提供的组件(例如,用 GestureDetector + DecoratedBox 自定义按钮) | 组合使用 Material 组件(FilledButton、OutlinedButton)并为其设置样式 |
使用自定义 InheritedWidget 创建平行的主题系统 | 以 Material 的 ThemeData 为基础,并使用 ThemeExtension 定义自定义令牌 |
在组件代码中硬编码 Color(0xFF...) | 标准颜色使用 Theme.of(context).colorScheme,自定义令牌使用 context.appColors |
在自定义类中重复定义 Material 的 ColorScheme 角色 | 仅为 Material 未涵盖的值创建 ThemeExtension 令牌(例如 success、warning、info) |
将 dynamic 或 Object 用作回调类型 | 使用 VoidCallback、ValueChanged<T> 或特定的函数 typedef |
| 直接公开内部实现文件 | 使用 barrel 文件;将 src/ 下的所有文件设为私有 |
创建软件包
使用 Very Good CLI MCP create 工具搭建框架:
| 参数 | 值 |
|---|---|
subcommand | app_ui_package — 所有 UI 软件包始终使用此值 |
name | 采用 snake_case 的软件包名称(例如,storefront_ui) |
output_directory | 存放共享软件包的 monorepo 目录(例如,packages/) |
app_ui_package 是随附 lib/src/theme 扩展、barrel 文件、pumpApp 助手和 Widgetbook 目录的模板。flutter_package 则提供一个空软件包,需要你手动重新构建。
跨环境备用方案。 如果主机没有此插件的 Bash hooks,也未连接 Very Good CLI MCP 服务,请直接运行等效命令
very_good create app_ui_package <package_name> --output-directory <dir>。
参阅 reference.md,了解 ThemeExtension 类表(AppColors、AppSpacing、AppTheme、BuildContext 扩展)、pumpApp 测试助手、barrel 文件示例、Widgetbook 目录概念和 build_runner 命令,以及添加组件或自定义令牌的分步工作流。