plugins/languages/flutter/skills/ui/SKILL.md
Flutter UI 开发规范 — Material 3 Expressive、Cupertino 自适应、响应式布局 (LayoutBuilder + MediaQuery.sizeOf)、Impeller 渲染优化、隐式/显式/Hero 动画、Widget 组合。当用户开发页面/组件/布局/主题、提到 "Widget"、"Material"、"Cupertino"、"动画"、"响应式"、"主题" 时加载。
npx skillsauth add lazygophers/ccplugin flutter-uiInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
class ProfilePage extends StatelessWidget {
const ProfilePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const ProfileAppBar(),
body: const Column(children: [
ProfileHeader(),
ProfileStats(),
ProfileActions(),
]),
);
}
}
原则: 单一职责、 const 最大化、拆分 ≤ 200 行子组件、可复用提取到 shared/widgets/。
class AdaptiveButton extends StatelessWidget {
const AdaptiveButton({super.key, required this.onPressed, required this.child});
final VoidCallback onPressed;
final Widget child;
@override
Widget build(BuildContext context) => switch (Theme.of(context).platform) {
TargetPlatform.iOS || TargetPlatform.macOS =>
CupertinoButton(onPressed: onPressed, child: child),
_ => ElevatedButton(onPressed: onPressed, child: child),
};
}
MaterialApp(
theme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),
darkTheme: ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
),
);
// 颜色/字体从 Theme 取 (禁硬编码)
Container(
color: Theme.of(context).colorScheme.primaryContainer,
child: Text('Hi', style: Theme.of(context).textTheme.headlineMedium),
);
// 简单
ListView.builder(
itemCount: users.length,
itemBuilder: (_, i) => RepaintBoundary(child: UserTile(user: users[i])),
);
// 复杂滚动 — CustomScrollView + Sliver
CustomScrollView(slivers: [
const SliverAppBar.large(title: Text('Users')),
SliverList.builder(
itemCount: users.length,
itemBuilder: (_, i) => UserTile(user: users[i]),
),
]);
class ResponsiveLayout extends StatelessWidget {
const ResponsiveLayout({super.key, required this.child});
final Widget child;
@override
Widget build(BuildContext context) => LayoutBuilder(
builder: (_, c) => switch (c.maxWidth) {
< 600 => MobileLayout(child: child),
< 1200 => TabletLayout(child: child),
_ => DesktopLayout(child: child),
},
);
}
// 推荐: 触发更少重建
MediaQuery.sizeOf(context).width;
MediaQuery.paddingOf(context);
// 避免: MediaQuery.of(context).size
class _MyWidgetState extends State<MyWidget> with SingleTickerProviderStateMixin {
late final AnimationController _ctrl;
late final StreamSubscription _sub;
@override
void initState() {
super.initState();
_ctrl = AnimationController(vsync: this, duration: const Duration(milliseconds: 300));
_sub = stream.listen(_onData);
}
@override
void dispose() {
_ctrl.dispose();
_sub.cancel();
super.dispose();
}
}
// 隐式
AnimatedContainer(
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOut,
width: isExpanded ? 200 : 100,
child: content,
);
// 显式
SlideTransition(
position: Tween<Offset>(begin: const Offset(-1, 0), end: Offset.zero)
.animate(CurvedAnimation(parent: _ctrl, curve: Curves.easeOut)),
child: content,
);
// 共享元素
Hero(
tag: 'user-${user.id}',
child: CircleAvatar(backgroundImage: NetworkImage(user.avatar)),
);
Opacity widget 触发 saveLayer → 用 color.withValues(alpha: ...) (Dart 3 替代 withOpacity)RepaintBoundary 隔离重绘cacheWidth/cacheHeight 降采样Skills(flutter:android) / Skills(flutter:ios) 的 Impeller 章节| AI 借口 | 实际检查 | 严重度 |
| --- | --- | --- |
| "Material 在 iOS 也行" | iOS 是否用 Cupertino? | 高 |
| "直接写颜色值" | 是否从 Theme.colorScheme 取? | 高 |
| "ListView 就够" | 大列表是否用 .builder? | 高 |
| "const 不重要" | 可 const 的 Widget 是否全标记? | 高 |
| "MediaQuery.of 就行" | 是否用 sizeOf/paddingOf 降重建? | 中 |
| "不需要 RepaintBoundary" | 复杂子树是否隔离? | 中 |
| "setState 更新 UI" | 是否该用 Riverpod/Bloc? | 高 |
ColorScheme.fromSeed()constListView.builder / SliverList.builderTheme 取LayoutBuilder + MediaQuery.sizeOf 响应式dispose 完整释放RepaintBoundary 隔离复杂子树Skills(flutter:core) / Skills(flutter:state)Skills(flutter:android) / Skills(flutter:ios) / Skills(flutter:web)tools
UI/UX 与布局设计——做界面布局/结构/导航/组件/交互的设计决策。触发:做UI/UX/布局/排版/导航/组件/交互/栅格/响应式/图表选型/字体配对。按媒介路由 HTML/Web、原生 App(iOS/Android/桌面)、CLI、TUI。需后端动态系统不适用;配色/主题/色板走姊妹 skill design-color。
tools
主题与配色设计——做颜色搭配/调色板/主题/品牌色阶/暗模式的设计决策。触发:选配色/调色/主题/色板/品牌色/暗模式/对比度/色盲/UI风格。按媒介路由 HTML/Web(CSS变量)、原生App(平台token)、CLI(ANSI)、TUI(真彩/256/16降级)。保证可访问性(对比度/色盲安全)。需后端动态系统不适用;UI/UX 布局/组件/交互走姊妹 skill design-uiux。
tools
跨任意组件(plugin/skill/agent/command)的验证驱动优化循环纪律 skill。当用户要优化某个已有组件却无明确方向、或要防止改了反而更差(自评乐观偏差 / 多维同改归因失效 / 为凑分加废话膨胀)、或要把一套通用「评分→单变量改→改后验证严格更好才留否则回滚→触顶停」的纪律套到任意组件上时使用。管优化过程本身的纪律(validation gate / ratchet / 独立验证 / 触顶停),不评单组件深度(交 skill-dev),不查插件接线(交 plugin-dev)。仅手动 /optimize-any 触发。
data-ai
两层规则记忆 (基于 .skein/spec)。planning 时 recall 召回相关规则、task finish 后 sediment 沉淀学习 + prune 自动精简过期/重复/断链规则。core 常驻硬规 + recall 按需召回, 经判定门自动写盘 (不逐次问用户)。产出 .skein/spec 下 core/recall 规则文件 + index。另支持空仓 bootstrap 播种规则基线、记忆大面积失效 (大重构/换栈) 时 reconstruct 可逆归档后按项目类型分型重建、maintain 手动体检 (超预算/stale/断链/重复/废弃, --apply 自动修复)、auto-fix (Stop hook 写 .pending-fix 标记 → main 派 skein-specer bg 跑 maintain --apply 全自动修, 断链只报告)。