base_ui 详细文档
概述
base_ui 是 FluCli 项目模板的核心UI基础架构,通过统一的页面基类和组件封装,为Flutter应用提供标准化的开发模式。本文档将深入介绍base_ui的设计原理、使用方法和最佳实践。
🎯 设计理念
界面设计的三层决策模型
界面设计是一个复杂的过程,涉及多个决策因素,为了确保设计的一致性和可维护性,我们采用了三层决策模型:基础框架选择、内容性质定义和交互方式确定。
1. 基础框架选择:界面类型
界面设计的首要决策是确定整体框架,主要分为两种情况:
- 有AppBar的页面:适用于需要全局导航和操作的场景
- 无AppBar的页面:适用于沉浸式内容展示场景
2. 内容性质定义:内容类型
在确定基础框架后,需根据内容性质进行分类:
- 数据页面:以展示结构化数据为主,如表格、列表等
- 状态页面:以传递特定状态信息为主,如空状态、加载状态等
3. 交互方式确定:显示方式
最后根据内容体量和交互需求决定显示方式:
- 可滚动的页面:如列表页等内容较长的场景
- 不可滚动的页面:如详情页等内容聚焦的场景
基于以上的需求,我们提供一套相对完善的Mixin供开发者使用,开发者可以根据自己的需求选择使用
dart
HzyScaffolMixin, // 脚手架混入
HzyAppBarMixin, // 导航栏混入
HzyBodyMixin, // 主体内容混入
HzyAbsAttribute, // 抽象属性混入
HzyAbstractNetWork, // 网络请求混入
HzyNormalLifeCycleAbs, // 生命周期混入
HzyAbsState, // 界面状态混入
HzyAbstracRefreshWidget, // 刷新组件混入
HzyAbstracRefreshMehod, // 刷新触发方法混入
HzyAbstractNetWork, // 网络请求混入
通过以上的Mixin,开发者可以快速搭建一个具备基础功能的页面,开发者也可以根据自己的需求,选择混入其他的Mixin,来扩展页面的功能
基于以上的Mixin,base_ui提供两种状态管理实现方案
- 基于Flutter原生状态管理
base_normal_ui
- 基于GetX状态管理
base_getx_ui
如果想要了解更多关于Mixin的详细信息,请参考Mixin详细文档
核心目标
- 统一性:提供一致的页面结构和交互模式
- 复用性:减少重复代码,提高开发效率
- 扩展性:支持灵活的自定义和扩展
- 维护性:降低项目维护成本
注意
- base_ui 是一个基础架构,不包含具体的业务逻辑。
- 开发者可以根据项目需求,选择合适的状态管理方案(base_normal_ui 或 base_getx_ui)。
📚 base_ui 基础类
基于开发过程中,频繁使用的场景,提供无状态、有状态以及布局相关的组件基类和界面基类
base_normal_ui
基于Flutter原生状态管理方案
无状态
BaseLessV
无状态界面基类BaseLessWidget
无状态组件基类
有状态
BaseStateV
有状态界面基类BaseStateWidget
有状态组件基类BaseListStateV
列表界面基类BaseListStateWidget
列表组件基类
布局相关
BaseLayoutStateV
布局有状态界面基类BaseLayoutStateWidget
布局有状态组件基类BaseLayoutLessV
布局无状态界面基类BaseLayoutLessWidget
布局无状态组件基类
base_getx_ui
基于GetX状态管理方案
- 界面
BaseGetXV
基于GetX界面基类BaseGetXlistV
基于GetX界面列表基类
- 控制器
BaseGetXController
基于GetX控制器基类BaseGetXListController
基于GetX列表控制器基类
🏗️ base_normal_ui 介绍和使用
BaseStateV - 完整页面基类
BaseStateV
是功能最完整的页面基类,集成了多个Mixin提供丰富功能:
dart
abstract class BaseStateV<T extends StatefulWidget> extends State<T>
with
HzyScaffolMixin, // 脚手架混入
HzyAppBarMixin, // 导航栏混入
HzyBodyMixin, // 主体内容混入
HzyAbsAttribute, // 抽象属性混入
HzyAbstractNetWork, // 网络请求混入
HzyNormalLifeCycleAbs,// 生命周期混入
WidgetsBindingObserver // 应用生命周期观察者
核心功能特性
功能模块 | 说明 | 使用场景 |
---|---|---|
页面状态管理 | 支持初始化、加载中、成功、失败、空数据状态 | 所有需要状态管理的页面 |
缺省页面 | 统一的加载、错误、空数据页面 | 网络请求页面 |
安全区域 | 自动处理刘海屏和底部安全区域 | 全屏页面 |
生命周期 | 完整的页面和应用生命周期管理 | 需要监听生命周期的页面 |
主题适配 | 支持亮色/暗色主题切换 | 所有页面 |
想了解更多base_normal_ui
的详细信息,请查看base_normal_ui。
🚀 GetX base_getx_ui 介绍和使用
BaseGetXController - 控制器基类
基于GetX的控制器基类,提供响应式状态管理:
dart
class HomeController extends BaseGetXController {
// 响应式数据
var userList = <User>[].obs;
var isLoading = false.obs;
@override
void onInit() {
super.onInit();
loadUsers();
}
void loadUsers() async {
try {
isLoading.value = true;
pageState.value = PageState.loadingState;
final users = await UserApi.getUsers();
userList.value = users;
pageState.value = PageState.successState;
} catch (e) {
pageState.value = PageState.errorState;
placeMsg = '加载失败,请重试';
} finally {
isLoading.value = false;
}
}
void refreshData() {
loadUsers();
}
@override
void tapPlaceHoldWidgetMethod({required CommonPlaceHoldType placeHoldType}) {
// 缺省页面点击处理
if (placeHoldType == CommonPlaceHoldType.errorData) {
loadUsers();
}
}
}
BaseGetXV - 视图基类
基于GetX的视图基类,支持响应式UI更新:
dart
class HomePage extends BaseGetXV<HomeController> {
@override
Widget createBody(BuildContext context) {
return Obx(() {
if (controller.isLoading.value) {
return Center(child: CircularProgressIndicator());
}
return ListView.builder(
itemCount: controller.userList.length,
itemBuilder: (context, index) {
final user = controller.userList[index];
return ListTile(
title: Text(user.name),
subtitle: Text(user.email),
onTap: () => Get.to(() => UserDetailPage(user: user)),
);
},
);
});
}
@override
String? createAppBarTitle() => '用户列表';
@override
bool get isShowAppBar => true;
@override
List<Widget>? createAppBarActions() {
return [
IconButton(
icon: Icon(Icons.refresh),
onPressed: () => controller.refreshData(),
),
];
}
}
路由绑定
dart
// 在路由配置中绑定控制器
GetPage(
name: '/home',
page: () => HomePage(),
binding: BindingsBuilder(() {
Get.lazyPut<HomeController>(() => HomeController());
}),
),
🎨 主题和样式定制
主题配置
dart
// 在BaseStateV中重写主题相关方法
class _HomePageState extends BaseStateV<HomePage> {
@override
Color? createScaffoldBackgroundColor() {
return Theme.of(context).colorScheme.background;
}
@override
Color? createAppBarBackgroundColor() {
return Theme.of(context).primaryColor;
}
@override
bool get isDarkStatusBar => Theme.of(context).brightness == Brightness.light;
}
自定义缺省页面
dart
@override
Widget? createEmptyWidget() {
return CustomEmptyWidget(
icon: Icons.inbox,
title: '暂无数据',
subtitle: '点击刷新重新加载',
onRefresh: () => loadData(),
);
}
🔧 高级功能
网络请求集成
dart
class _ApiPageState extends BaseStateV<ApiPage> {
@override
void configDefault() {
super.configDefault();
// 使用内置网络请求方法
requestData();
}
void requestData() async {
await requestMethod(
request: () => ApiService.getData(),
onSuccess: (data) {
// 请求成功处理
setState(() {
pageState = PageState.successState;
});
},
onError: (error) {
// 请求失败处理
setState(() {
pageState = PageState.errorState;
errMsg = error.toString();
});
},
);
}
}
生命周期监听
dart
class _LifeCyclePageState extends BaseStateV<LifeCyclePage> {
@override
void configAppLifeCycleResumed() {
// 应用进入前台
print('应用进入前台');
refreshData();
}
@override
void configAppLifeCyclePaused() {
// 应用进入后台
print('应用进入后台');
saveData();
}
@override
void interfaceRenderingCompleted() {
// 界面渲染完成
print('界面渲染完成');
loadInitialData();
}
}
想了解更多base_getx_ui
的详细信息,请查看base_getx_ui。
📋 最佳实践
1. 选择合适的基类
场景 | 推荐基类 | 理由 |
---|---|---|
完整页面 | BaseStateV / BaseGetXV | 功能完整,支持所有特性 |
自定义组件 | BaseStateWidget | 轻量级,性能更好 |
列表页面 | BaseListState / BaseGetXListV | 内置列表功能 |
简单页面 | BaseStateWidget | 减少不必要的功能 |
2. 状态管理规范
dart
// 好的做法
class _GoodPageState extends BaseStateV<GoodPage> {
@override
void configDefault() {
super.configDefault();
// 在这里进行初始化
initData();
}
void initData() async {
setState(() {
pageState = PageState.loadingState;
});
try {
final data = await loadData();
setState(() {
pageState = PageState.successState;
});
} catch (e) {
setState(() {
pageState = PageState.errorState;
errMsg = e.toString();
});
}
}
}
3. 错误处理
dart
@override
void tapPlaceHoldWidgetMethod({required CommonPlaceHoldType placeHoldType}) {
switch (placeHoldType) {
case CommonPlaceHoldType.errorData:
// 重新加载数据
loadData();
break;
case CommonPlaceHoldType.emptyData:
// 跳转到添加页面
Navigator.push(context, MaterialPageRoute(builder: (_) => AddPage()));
break;
case CommonPlaceHoldType.networkError:
// 检查网络设置
showNetworkSettingsDialog();
break;
}
}
4. 性能优化
dart
class _OptimizedPageState extends BaseStateV<OptimizedPage> {
@override
void dispose() {
// 清理资源
controller?.dispose();
timer?.cancel();
super.dispose();
}
@override
bool get wantKeepAlive => true; // 保持页面状态
}
🚨 常见问题
Q: 如何在base_ui中使用自定义AppBar?
dart
@override
PreferredSizeWidget? createAppBar() {
return CustomAppBar(
title: '自定义标题',
actions: [
IconButton(
icon: Icon(Icons.search),
onPressed: () => showSearch(),
),
],
);
}
Q: 如何禁用某些默认功能?
dart
@override
bool get isShowAppBar => false; // 不显示AppBar
@override
bool get isNeedSafe => false; // 不需要安全区域
@override
bool get safeAreaBottom => false; // 底部不需要安全区域
Q: 如何在GetX版本中处理页面跳转?
dart
// 在Controller中
void goToDetail(String id) {
Get.toNamed('/detail', arguments: {'id': id});
}
// 在View中
ElevatedButton(
onPressed: () => controller.goToDetail('123'),
child: Text('查看详情'),
)
通过合理使用base_ui,您可以大幅提升Flutter应用的开发效率和代码质量!