关于 flutter-dev
为 Flutter 和 Dart 开发提供遵循 Flutter 官方团队实践的指导,适用于编写和维护应用的开发者。内容涵盖代码组织、状态管理、布局、导航、测试和无障碍设计。
主要功能
- 01遵循 SOLID 与 Dart 风格规范
- 02建议分层或按功能组织项目
- 03指导内置状态管理方案
- 04涵盖响应式布局与导航
- 05提供测试和代码分析建议
- 06包含无障碍与主题实践
适用场景
- 01规划 Flutter 项目结构
- 02实现响应式界面与导航
- 03选择状态管理和异步模式
- 04为应用编写测试并检查代码
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ bogdanustyak/ flutter-expert-skill --skill flutter-dev安装后在 Claude Code 中输入/flutter-dev确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdreferences/navigation_patterns.mdtheme_patterns.mdstate_patterns.md详细介绍
Flutter 开发专家
遵循 Flutter 团队的官方最佳实践,为 Flutter 和 Dart 开发提供专家指导。
核心开发原则
代码理念
- 在整个代码库中贯彻 SOLID 原则
- 使用函数式和声明式模式,编写简洁、现代、技术性强的 Dart 代码
- 构建复杂组件和逻辑时,优先使用组合而非继承
- 优先使用不可变数据结构,尤其是组件(尽可能使用
StatelessWidget) - 使用适当的状态管理方式,将临时状态与应用状态分离
- 保持函数简短且职责单一(尽量少于 20 行)
- 使用有意义且明确的名称,避免使用缩写
项目结构假设
- 使用标准 Flutter 项目结构,以
lib/main.dart作为入口点 - 按逻辑分层组织:表现层(组件/屏幕)、领域层(业务逻辑)、数据层(模型/API 客户端)、核心层(工具/扩展)
- 对于较大的项目:按功能组织,每个功能包含表现层/领域层/数据层子文件夹
交互指南
生成代码时:
- 解释 Dart 特有的功能(空安全、futures、streams)
- 如果请求含糊,请询问功能和目标平台的具体信息
- 建议使用 pub.dev 上的新依赖项时,说明其优点
- 使用
dart format工具统一格式 - 使用
dart fix工具自动修复常见错误 - 使用配置了推荐规则的 Dart 代码检查工具发现问题
代码质量标准
样式规则
- 行长度:不超过 80 个字符
- 命名约定:
- 类使用
PascalCase - 成员/变量/函数/枚举使用
camelCase - 文件使用
snake_case
- 类使用
- 不要添加行尾注释
- 简单的单行函数使用箭头语法
错误处理
- 预判并处理潜在错误,绝不静默失败
- 使用
try-catch代码块和适当的异常类型 - 针对特定代码情形使用自定义异常
- 正确使用
async/await,并进行可靠的错误处理
文档
- 为所有公共 API(类、构造函数、方法、顶层函数)添加
dartdoc注释 - 为复杂或不明显的代码编写清晰的注释
- 使用
///编写文档注释 - 以一个以句号结尾的单句摘要开头
- 说明代码为何以特定方式编写,而非说明代码做了什么
Dart 最佳实践
类型系统与空安全
- 编写健全的空安全代码
- 利用 Dart 的空安全功能
- 除非能确保值非空,否则避免使用
!运算符 - 在能简化代码时使用模式匹配功能
- 定义类过于繁琐时,使用记录返回多个类型
- 优先使用穷尽式
switch语句/表达式(无需break)
异步编程
- 对单次异步操作使用
Future、async、await - 对异步事件序列使用
Stream - 确保正确处理异步操作中的错误
类与库的组织
- 在同一个库文件中定义相关类
- 对于大型库:从单个顶层库导出较小的私有库
- 将相关库放在同一个文件夹中
Flutter 最佳实践
组件设计
- 组件(尤其是
StatelessWidget)不可变 - UI 需要变化时,Flutter 会重建组件树
- 优先组合较小的组件,而非扩展现有组件
- 使用小型私有
Widget类,而非返回组件的私有辅助方法 - 将大型
build()方法拆分为更小、可复用的私有 Widget 类 - 尽可能使用
const构造函数以减少重建
性能优化
- 长列表使用
ListView.builder或SliverList(惰性加载) - 使用
compute()在独立的 isolate 中运行耗时计算(例如 JSON 解析) - 避免在
build()方法中执行开销较大的操作(网络请求、复杂计算) - 在
build()方法中使用const构造函数,以尽可能减少重建
响应式设计
- 使用
LayoutBuilder或MediaQuery构建响应式 UI - 确保在不同屏幕尺寸下都能适配移动设备
- 在移动端和 Web 平台上进行测试
状态管理
除非明确要求使用第三方方案,否则优先使用 Flutter 内置方案:
内置方案(按简洁程度排序)
- ValueNotifier + ValueListenableBuilder - 用于单个值的简单局部状态
final ValueNotifier<int> _counter = ValueNotifier<int>(0);
ValueListenableBuilder<int>(
valueListenable: _counter,
builder: (context, value, child) => Text('Count: $value'),
);
- ChangeNotifier + ListenableBuilder - 用于跨多个组件的复杂或共享状态
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
ListenableBuilder(
listenable: counterModel,
builder: (context, child) => Text('${counterModel.count}'),
);
- Streams + StreamBuilder - 用于异步事件序列
- Futures + FutureBuilder - 用于单次异步操作
高级模式
- MVVM:Model-View-ViewModel 模式,适用于稳健的应用
- 依赖注入:使用手动构造函数注入,明确声明依赖项
- Provider:仅在明确要求使用手动注入之外的 DI 时采用
导航
GoRouter(推荐)
使用 go_router 实现声明式导航、深度链接和 Web 支持:
// Add dependency
flutter pub add go_router
// Configure router
final GoRouter _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => const HomeScreen(),
routes: [
GoRoute(
path: 'details/:id',
builder: (context, state) {
final String id = state.pathParameters['id']!;
return DetailScreen(id: id);
},
),
],
),
],
);
// Use in MaterialApp
MaterialApp.router(routerConfig: _router);
- 配置
redirect属性以处理身份验证流程 - 用于支持深度链接的路由
Navigator(内置)
用于无需深度链接的短期屏幕(对话框、临时视图):
Navigator.push(context, MaterialPageRoute(builder: (context) => DetailsScreen()));
Navigator.pop(context);
包管理
使用 pub 工具
- 添加依赖项:
flutter pub add <package_name> - 添加开发依赖项:
flutter pub add dev:<package_name> - 添加覆盖项:
flutter pub add override:<package_name>:1.0.0 - 移除依赖项:
dart pub remove <package_name>
外部包
- 在 pub.dev 上搜索合适且稳定的包
- 推荐新依赖项时说明其优势
数据处理
JSON 序列化
使用 json_serializable 和 json_annotation:
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonSerializable(fieldRename: FieldRename.snake)
class User {
final String firstName;
final String lastName;
User({required this.firstName, required this.lastName});
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
代码生成
- 确保
build_runner是开发依赖项 - 修改后运行:
dart run build_runner build --delete-conflicting-outputs
日志记录
使用 dart:developer 进行结构化日志记录:
import 'dart:developer' as developer;
// Simple messages
developer.log('User logged in successfully.');
// Structured error logging
try {
// code
} catch (e, s) {
developer.log(
'Failed to fetch data',
name: 'myapp.network',
level: 1000, // SEVERE
error: e,
stackTrace: s,
);
}
UI 与主题
Material Design 3 与 ThemeData
使用 ColorScheme.fromSeed() 创建协调的配色方案:
MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.deepPurple,
brightness: Brightness.light,
),
textTheme: TextTheme(
displayLarge: TextStyle(fontSize: 57, fontWeight: FontWeight.bold),
bodyMedium: TextStyle(fontSize: 14, height: 1.4),
),
),
darkTheme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.deepPurple,
brightness: Brightness.dark,
),
),
themeMode: ThemeMode.system,
);
自定义主题扩展
用于标准 ThemeData 之外的自定义设计令牌:
@immutable
class MyColors extends ThemeExtension<MyColors> {
const MyColors({required this.success, required this.danger});
final Color? success;
final Color? danger;
@override
ThemeExtension<MyColors> copyWith({Color? success, Color? danger}) {
return MyColors(success: success ?? this.success, danger: danger ?? this.danger);
}
@override
ThemeExtension<MyColors> lerp(ThemeExtension<MyColors>? other, double t) {
if (other is! MyColors) return this;
return MyColors(
success: Color.lerp(success, other.success, t),
danger: Color.lerp(danger, other.danger, t),
);
}
}
// Register in ThemeData
theme: ThemeData(
extensions: [MyColors(success: Colors.green, danger: Colors.red)],
),
// Use in widgets
Container(color: Theme.of(context).extension<MyColors>()!.success)
字体
使用 google_fonts 包设置自定义字体:
flutter pub add google_fonts
final TextTheme appTextTheme = TextTheme(
displayLarge: GoogleFonts.oswald(fontSize: 57, fontWeight: FontWeight.bold),
titleLarge: GoogleFonts.roboto(fontSize: 22, fontWeight: FontWeight.w500),
bodyMedium: GoogleFonts.openSans(fontSize: 14),
);
图像与资源
在 pubspec.yaml 中声明:
flutter:
uses-material-design: true
assets:
- assets/images/
// Local images
Image.asset('assets/images/placeholder.png')
// Network images (always include error handling)
Image.network(
'https://example.com/image.png',
loadingBuilder: (context, child, progress) {
if (progress == null) return child;
return Center(child: CircularProgressIndicator());
},
errorBuilder: (context, error, stackTrace) => Icon(Icons.error),
)
布局最佳实践
灵活布局
- Expanded:填满 Row/Column 中的剩余空间
- Flexible:收缩以适应内容(不要与 Expanded 组合使用)
- Wrap:溢出时自动换到下一行
- SingleChildScrollView:用于大于视口的固定尺寸内容
- ListView.builder/GridView.builder:用于长列表(延迟加载)
- FittedBox:在父组件内缩放或适配单个子组件
- LayoutBuilder:根据可用空间构建响应式布局
Stack 布局
- Positioned:通过锚定边缘精确放置子组件
- Align:使用对齐方式放置(例如,Alignment.center)
覆盖层
使用 OverlayPortal 在所有内容之上显示 UI 元素:
final _controller = OverlayPortalController();
OverlayPortal(
controller: _controller,
overlayChildBuilder: (context) => Positioned(
top: 50,
left: 10,
child: Card(child: Text('Overlay content')),
),
child: ElevatedButton(
onPressed: _controller.toggle,
child: Text('Toggle'),
),
)
视觉设计原则
设计指南
- 构建美观、直观且符合现代设计的 UI
- 确保适配不同屏幕尺寸(移动端和 Web)
- 提供直观的导航
- 运用字体层级(主视觉文本、标题、关键词)
- 添加细腻的背景纹理,营造高级质感
- 使用多层阴影增强层次感
- 添加图标以提升理解度
- 为交互元素添加阴影和色彩光晕效果
色彩指南
- 60-30-10 法则:60% 主色/中性色、30% 次要色、10% 强调色
- 对比度比例(WCAG 2.1):
- 普通文本:至少 4.5:1
- 大号文本(18pt 或 14pt 粗体):至少 3:1
- 避免将互补色用于文本/背景(会造成视觉疲劳)
- 谨慎使用互补色作为强调色
字体排印
- 限制使用 1-2 种字体系列
- 优先保证易读性(UI 正文使用无衬线字体)
- 行高:字体大小的 1.4 倍至 1.6 倍
- 行长:正文每行 45-75 个字符
- 避免长篇文本全部使用大写字母
测试
测试类型
- 单元测试:使用
package:test测试领域逻辑、数据层和状态管理 - Widget 测试:使用
package:flutter_test测试 UI 组件 - 集成测试:使用
package:integration_test测试端到端流程
测试最佳实践
- 遵循 Arrange-Act-Assert(Given-When-Then)模式
- 优先使用
package:checks,以编写更具表现力的断言 - 优先使用 fake/stub,而非 mock
- 如有必要使用 mock:使用
mockito或mocktail - 力求实现较高的测试覆盖率
- 编写易于测试的代码:使用
file、process、platform包进行依赖注入
运行测试
flutter test
无障碍(A11y)
- 色彩对比度:文本与背景的对比度至少为 4.5:1
- 动态文本缩放:使用增大的系统字体测试 UI
- 语义标签:使用
Semanticswidget 设置清晰、明确的标签 - 屏幕阅读器测试:使用 TalkBack(Android)和 VoiceOver(iOS)进行测试
分析与 Lint
在 analysis_options.yaml 中添加:
include: package:flutter_lints/flutter.yaml
linter:
rules:
# Add additional lint rules here
其他资源
如需查看详细模式和示例,请参阅:
references/navigation_patterns.md- 使用 GoRouter 的高级导航模式references/state_patterns.md- 全面的状态管理示例references/theme_patterns.md- 高级主题与样式模式
评论
支持 Markdown