Mixin
概述
Mixin 是 FluCli 项目模板中的重要设计模式,它通过代码复用的方式,将通用功能抽象为可混入的类,从而避免了多重继承的复杂性,同时保持了代码的模块化和可维护性。本文档将详细介绍 FluCli 项目中的 Mixin 设计和使用方法。
Mixin 基础
什么是 Mixin
Mixin 是 Dart 语言提供的一种代码复用机制,它允许类在不使用继承的情况下复用其他类的代码。在 Flutter 开发中,Mixin 特别适用于:
- 横切关注点:如日志记录、权限检查、生命周期管理
- 功能组合:将多个独立功能组合到一个类中
- 避免深层继承:减少继承层次,提高代码可维护性
设计原则
我们的 Mixin 设计遵循以下原则:
- 单一职责:每个 Mixin 只负责一个特定功能
- 可组合性:多个 Mixin 可以自由组合使用
- 可配置性:提供丰富的配置选项满足不同需求
- 向后兼容:保持 API 稳定性
核心 Mixin 类
1. HzyScaffolMixin - 脚手架混入
功能说明:提供 Scaffold 脚手架的统一管理,包括是否需要脚手架、背景色配置、导航栏配置等。
设计目的:
- 统一管理页面的基础结构
- 提供灵活的脚手架配置选项
- 支持自定义背景色和键盘弹起行为
- 支持自定义 AppBar 配置
mixin HzyScaffolMixin {
/// 创建脚手架
createScaffolWidget({
required BuildContext context,
BoxConstraints? constraints,
}) {
Widget body = configIsNeedScaffol()
? Scaffold(
appBar: createAppBar(context: context),
backgroundColor: configScallBackgroundColor(),
resizeToAvoidBottomInset: configResizeToAvoidBottomInset(),
body: createScallBody(
context: context,
constraints: constraints,
),
)
: createScallBody(
context: context,
constraints: constraints,
);
return body;
}
/// 创建导航栏
@protected
PreferredSizeWidget? createAppBar({
required BuildContext context,
});
/// 创建界面body
@protected
Widget createScallBody({
required BuildContext context,
BoxConstraints? constraints,
});
}
使用示例:
class MyPage extends StatefulWidget {}
class _MyPageState extends State<MyPage> with HzyScaffolMixin {
@override
bool configIsNeedScaffol() => true;
@override
Color? configScallBackgroundColor() => Colors.white;
}
扩展优势:
- 新增脚手架配置时,只需在 Mixin 中添加方法
- 所有使用该 Mixin 的页面自动获得新功能
- 可以根据业务需求灵活开启或关闭脚手架
2. HzyAppBarMixin - 导航栏混入
功能说明:统一管理 AppBar 的创建和配置,包括标题、颜色、按钮等。
设计目的:
- 标准化 AppBar 的创建流程
- 提供丰富的自定义选项
- 支持动态配置导航栏样式(如标题、颜色、按钮等)
mixin HzyAppBarMixin {
/// 创建导航栏
PreferredSizeWidget? createAppBar({
required BuildContext context,
})
/// 创建导航栏标题
String? createAppBarTitleStr() => null;
/// 配置导航栏背景色
Color? createAppBarNavBackColor() => null;
/// 配置右侧按钮
List<Widget>? createAppBaractions() => null;
/// 是否显示返回按钮
bool configShowBack() => true;
/// 配置导航栏标题颜色
Color? createAppBarTitleColor() => null;
}
通过对比 HzyScaffolMixin
和 HzyAppBarMixin
,我们可以发现:
HzyScaffolMixin
实现了createScaffolWidget
方法,并提供了脚手架的能力。HzyAppBarMixin
实现了createAppBar
方法,并提供了自定义导航栏的能力。这样我们就可以利用方法重写的方法,就实现了AppBar
功能,如果你想自定义,也只需要重写createAppBar
方法,其他的方法,你可以根据自己的需求,来定制化。
使用示例:
class _MyPageState extends State<MyPage>
with HzyScaffolMixin, HzyAppBarMixin {
@override
String? createAppBarTitleStr() => "我的页面";
@override
Color? createAppBarNavBackColor() => Colors.blue;
@override
List<Widget>? createAppBaractions() => [
IconButton(
icon: Icon(Icons.settings),
onPressed: () => print("设置"),
),
];
}
扩展优势:
- 支持完全自定义 AppBar 的每个部分
- 可以统一修改全局 AppBar 样式
- 新增功能时不影响现有页面
3. HzyBodyMixin - 页面主体混入
HzyBodyMixin
是页面主体内容的核心管理者,负责处理页面的主要显示逻辑,包括安全区域处理、页面状态管理、占位图显示等功能。
核心功能
- 🛡️ 安全区域管理:自动处理刘海屏、底部指示器等安全区域适配
- 📊 页面状态管理:统一管理加载、成功、失败、空数据等页面状态
- 🎭 占位图系统:提供加载动画、错误提示、空状态等占位组件
- 🔧 高度可配置:丰富的配置选项满足不同场景需求
基本使用
class _MyPageState extends State<MyPage>
with HzyScaffolMixin, HzyAppBarMixin, HzyBodyMixin {
PageState _pageState = PageState.loadingState;
// 配置方法
@override
bool configIsNeedSafeArea() => true;
@override
PageState configPageState() => _pageState;
// 实现页面内容
@override
Widget createBody({required BuildContext context, BoxConstraints? constraints}) {
return ListView(
children: [
// 您的页面内容
],
);
}
}
设计优势
- 减少重复代码:统一的页面结构和状态管理
- 提升开发效率:专注业务逻辑,无需关心基础架构
- 保证用户体验:全局一致的加载、错误、空状态样式
- 便于维护扩展:集中管理页面状态逻辑
详细了解
想要深入了解 HzyBodyMixin
的完整功能、界面构建流程、配置选项和高级用法,请查看:
包含完整的流程图、方法调用链、可视化层级结构、配置说明、使用示例和最佳实践。
4. HzyLayoutMixin - 布局混入
功能说明:提供 LayoutBuilder 的封装,用于响应式布局设计。
设计目的:
- 支持响应式布局开发
- 提供屏幕尺寸适配能力
- 简化 LayoutBuilder 的使用
mixin HzyLayoutMixin {
/// 是否需要 Layout
bool configIsNeedLayout() => true;
/// 创建布局子组件
Widget createLayoutChileWidget({
BoxConstraints? constraints,
required BuildContext context,
});
}
使用示例:
class _MyPageState extends State<MyPage> with HzyLayoutMixin {
@override
Widget createLayoutChileWidget({
BoxConstraints? constraints,
required BuildContext context,
}) {
// 根据屏幕宽度调整布局
if (constraints!.maxWidth > 600) {
return _buildTabletLayout();
} else {
return _buildPhoneLayout();
}
}
}
5. HzyAbsAttribute - 属性抽象混入
功能说明:定义页面的通用属性配置,如导航栏显示、安全区域、背景色等。
设计目的:
- 提供统一的属性配置接口
- 减少重复的属性定义
- 支持默认值和自定义配置
mixin class HzyAbsAttribute {
/// 是否显示导航栏
final bool isShowAppBar = true;
/// 导航栏标题
final String? appBarTitle = null;
/// 安全区域配置
final bool safeAreaTop = true;
final bool safeAreaBottom = true;
/// 背景颜色
final Color? scallBackGroundColor = null;
}
6. HzyNormalLifeCycleAbs - 生命周期混入
功能说明:提供应用生命周期的统一管理,包括前台、后台切换等。
设计目的:
- 统一应用生命周期处理
- 提供生命周期回调钩子
- 支持主题和语言变更监听
mixin class HzyNormalLifeCycleAbs {
/// 应用进入前台
configAppLifeCycleResumed() {}
/// 应用进入后台
configAppLifeCyclePaused() {}
/// 主题变更回调
configPlatformBrightness() {}
/// 语言变更回调
configChangeLocales(List<Locale>? locales) {}
}
7. HzyAbstractNetWork - 网络请求混入
功能说明:提供网络请求的统一接口和处理机制。
设计目的:
- 标准化网络请求流程
- 提供统一的错误处理
- 支持请求参数的灵活配置
mixin class HzyAbstractNetWork {
/// 网络请求统一入口
@protected
getNetWorkData({
int? type,
Map<String, dynamic>? info,
}) {
// 实现网络请求逻辑
}
}
INFO
想要查看完整的Mixin
代码,可以查看hzy_normal_tool中的lib/hzy_normal_abstract
文件夹.
实际应用示例
完整的页面实现
/// 完整的页面实现示例
class MyComplexPage extends StatefulWidget {
@override
_MyComplexPageState createState() => _MyComplexPageState();
}
class _MyComplexPageState extends State<MyComplexPage>
with
HzyScaffolMixin,
HzyAppBarMixin,
HzyBodyMixin,
HzyLayoutMixin,
HzyAbsAttribute,
HzyAbstractNetWork,
HzyNormalLifeCycleAbs,
WidgetsBindingObserver {
PageState _pageState = PageState.initializedState;
List<String> _dataList = [];
@override
void initState() {
super.initState();
_loadData();
}
/// 网络请求实现
@override
getNetWorkData({int? type, Map<String, dynamic>? info}) {
// 模拟网络请求
Future.delayed(Duration(seconds: 2), () {
setState(() {
_dataList = ["数据1", "数据2", "数据3"];
_pageState = PageState.dataState;
});
});
}
void _loadData() {
setState(() {
_pageState = PageState.loadingState;
});
getNetWorkData(type: 1);
}
/// AppBar 配置
@override
String? createAppBarTitleStr() => "复杂页面示例";
@override
List<Widget>? createAppBaractions() => [
IconButton(
icon: Icon(Icons.refresh),
onPressed: _loadData,
),
];
/// 页面状态配置
@override
PageState configPageState() => _pageState;
@override
Widget? createEmptyWidget() => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.inbox, size: 64, color: Colors.grey),
SizedBox(height: 16),
Text("暂无数据", style: TextStyle(color: Colors.grey)),
SizedBox(height: 16),
ElevatedButton(
onPressed: _loadData,
child: Text("重新加载"),
),
],
),
);
@override
Widget? createLoadingWidget() => Center(
child: CircularProgressIndicator(),
);
/// 主体内容
@override
Widget createBody({required BuildContext context, BoxConstraints? constraints}) {
return ListView.builder(
itemCount: _dataList.length,
itemBuilder: (context, index) => ListTile(
leading: CircleAvatar(child: Text('${index + 1}')),
title: Text(_dataList[index]),
trailing: Icon(Icons.arrow_forward_ios),
onTap: () => print("点击了 ${_dataList[index]}"),
),
);
}
/// 生命周期回调
@override
configAppLifeCycleResumed() {
print("页面回到前台,可以刷新数据");
}
@override
Widget build(BuildContext context) {
return createBuild(context: context);
}
}
设计优势
1. 模块化设计
每个 Mixin 都专注于特定功能,可以独立开发、测试和维护:
- HzyScaffolMixin:专注脚手架管理
- HzyAppBarMixin:专注导航栏配置
- HzyBodyMixin:专注页面状态管理
- HzyLayoutMixin:专注响应式布局
2. 灵活组合
开发者可以根据页面需求选择性地混入不同的 Mixin:
// 简单页面:只需要基础功能
class SimplePage extends StatefulWidget {}
class _SimplePageState extends State<SimplePage>
with HzyScaffolMixin, HzyAppBarMixin {
// 实现简单页面
}
// 复杂页面:需要完整功能
class ComplexPage extends StatefulWidget {}
class _ComplexPageState extends State<ComplexPage>
with HzyScaffolMixin, HzyAppBarMixin, HzyBodyMixin,
HzyLayoutMixin, HzyAbsAttribute {
// 实现复杂页面
}
3. 易于扩展
当需要新增功能时,只需要:
- 在对应 Mixin 中添加新方法
- 提供默认实现
- 在需要的页面中重写方法
// 在 HzyAppBarMixin 中新增功能
mixin HzyAppBarMixin {
// 现有方法...
/// 新增:配置导航栏阴影
double? createAppBarElevation() => null;
/// 新增:配置导航栏形状
ShapeBorder? createAppBarShape() => null;
}
4. 统一标准
通过 Mixin 统一了页面开发标准:
- 命名规范:所有配置方法以
config
开头,创建方法以create
开头 - 参数传递:统一的参数传递方式
- 生命周期:标准化的生命周期管理
- 状态管理:统一的页面状态定义
5. 向后兼容
新增功能时保持向后兼容:
- 默认实现:新方法提供合理的默认值
- 可选重写:开发者可选择性地重写需要的方法
- 渐进升级:可以逐步迁移到新功能
最佳实践
1. 合理选择 Mixin
根据页面复杂度选择合适的 Mixin 组合:
// ✅ 好的做法:根据需求选择
class SimpleListPage extends StatefulWidget {}
class _SimpleListPageState extends State<SimpleListPage>
with HzyScaffolMixin, HzyAppBarMixin, HzyBodyMixin {
// 只混入需要的功能
}
// ❌ 避免:不必要的 Mixin
class SimpleListPage extends StatefulWidget {}
class _SimpleListPageState extends State<SimpleListPage>
with HzyScaffolMixin, HzyAppBarMixin, HzyBodyMixin,
HzyLayoutMixin, HzyAbsAttribute, HzyAbstractNetWork {
// 混入了过多不需要的功能
}
2. 重写关键方法
重写 Mixin 中的关键方法来定制页面行为:
class _MyPageState extends State<MyPage> with HzyBodyMixin {
@override
bool configIsNeedSafeArea() => false; // 不需要安全区域
@override
PageState configPageState() => _currentState; // 动态状态
@override
Widget? createEmptyWidget() => CustomEmptyWidget(); // 自定义空状态
}
3. 保持方法简洁
Mixin 中的方法应该保持简洁,复杂逻辑放在具体实现中:
// ✅ 好的做法
@override
String? createAppBarTitleStr() => "我的页面";
@override
Color? createAppBarNavBackColor() => Theme.of(context).primaryColor;
// ❌ 避免:在 Mixin 方法中写复杂逻辑
@override
Widget? createEmptyWidget() {
// 避免在这里写大量业务逻辑
return _buildComplexEmptyWidget();
}
Widget _buildComplexEmptyWidget() {
// 复杂逻辑放在单独方法中
return Container(/* 复杂的空状态组件 */);
}
4. 利用组合优势
充分利用 Mixin 的组合特性,创建可复用的页面模板:
/// 基础页面模板
abstract class BasePageState<T extends StatefulWidget> extends State<T>
with HzyScaffolMixin, HzyAppBarMixin, HzyBodyMixin {
@override
bool configIsNeedScaffol() => true;
@override
Color? configScallBackgroundColor() => Colors.white;
}
/// 列表页面模板
abstract class BaseListPageState<T extends StatefulWidget> extends BasePageState<T>
with HzyAbstractNetWork {
@override
Widget? createLoadingWidget() => Center(child: CircularProgressIndicator());
}
/// 具体页面实现
class _UserListPageState extends BaseListPageState<UserListPage> {
@override
String? createAppBarTitleStr() => "用户列表";
@override
Widget createBody({required BuildContext context, BoxConstraints? constraints}) {
return ListView.builder(/* 用户列表实现 */);
}
}
总结
Mixin 设计模式在 Flutter 开发中提供了强大的代码复用能力。通过合理的 Mixin 设计,我们实现了:
- 代码复用:避免重复编写相同的页面结构代码
- 模块化:每个 Mixin 专注特定功能,易于维护
- 灵活组合:根据需求自由组合不同功能
- 统一标准:建立了统一的页面开发规范
- 易于扩展:新增功能时不影响现有代码
这种设计方式特别适合大型项目的开发,能够显著提高开发效率和代码质量。