FluCli 实战示例
概述
本文档将通过一个实际的示例,展示如何使用 FluCli 创建项目,并分别使用 base_normal_ui
和 base_getx_ui
两种状态管理方案实现相同的功能。通过这个示例,您将了解两种方案的异同,以及如何根据项目需求选择合适的方案。
准备工作
安装 FluCli
首先,我们需要安装 FluCli 工具:
bash
# 使用 npm 全局安装
npm install -g flu-cli
# 或使用 yarn 全局安装
yarn global add flu-cli
# 或使用 pnpm 全局安装
pnpm add -g flu-cli
创建项目
使用 FluCli 创建一个新项目:
bash
# 启动交互式向导
flu-cli
按照向导提示,选择以下配置:
- 项目类型:应用 (app)
- 项目模板:pro (包含完整功能)
- 状态管理:根据需要选择 state 或 get
- 输入项目名称:flucli_example
- 输入包名:com.example.flucli_example
- 选择项目存放路径
- 选择要打开的 IDE
提示
如果您想同时体验两种状态管理方案,可以创建两个项目,分别选择 state 和 get 状态管理。
示例功能介绍
我们将实现一个简单的待办事项列表应用,包含以下功能:
- 显示待办事项列表
- 添加新的待办事项
- 标记待办事项为已完成
- 删除待办事项
使用 base_normal_ui 实现
创建数据模型
首先,我们需要创建一个待办事项的数据模型:
dart
// lib/models/todo_model.dart
class TodoModel {
final int id;
final String title;
bool completed;
TodoModel({
required this.id,
required this.title,
this.completed = false,
});
TodoModel copyWith({
int? id,
String? title,
bool? completed,
}) {
return TodoModel(
id: id ?? this.id,
title: title ?? this.title,
completed: completed ?? this.completed,
);
}
}
创建待办事项列表页面
使用 base_normal_ui
创建待办事项列表页面:
dart
// lib/pages/todo_list_page.dart
import 'package:flutter/material.dart';
import 'package:flucli_example/common/base_ui/base_normal_ui/base_list_state.dart';
import 'package:flucli_example/models/todo_model.dart';
class TodoListPage extends StatefulWidget {
const TodoListPage({Key? key}) : super(key: key);
@override
_TodoListPageState createState() => _TodoListPageState();
}
class _TodoListPageState extends BaseListState<TodoListPage> {
final TextEditingController _textController = TextEditingController();
@override
void configDefault() {
super.configDefault();
appBarTitle = '待办事项';
// 初始化一些示例数据
dataList = [
TodoModel(id: 1, title: '学习 Flutter'),
TodoModel(id: 2, title: '学习 FluCli'),
TodoModel(id: 3, title: '学习 base_normal_ui'),
];
// 设置页面状态为成功
pageState = PageState.successState;
}
@override
Widget buildSuccessContent() {
return Column(
children: [
_buildAddTodoInput(),
Expanded(
child: ListView.builder(
itemCount: dataList.length,
itemBuilder: (context, index) {
return createListItem(index: index, dataList: dataList);
},
),
),
],
);
}
Widget _buildAddTodoInput() {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _textController,
decoration: InputDecoration(
hintText: '添加新的待办事项',
border: OutlineInputBorder(),
),
),
),
SizedBox(width: 16),
ElevatedButton(
onPressed: _addTodo,
child: Text('添加'),
),
],
),
);
}
void _addTodo() {
if (_textController.text.isNotEmpty) {
setState(() {
dataList.add(TodoModel(
id: dataList.length + 1,
title: _textController.text,
));
_textController.clear();
});
}
}
void _toggleTodo(int index) {
setState(() {
final todo = dataList[index] as TodoModel;
dataList[index] = todo.copyWith(completed: !todo.completed);
});
}
void _deleteTodo(int index) {
setState(() {
dataList.removeAt(index);
});
}
@override
Widget createListItem({required int index, required List dataList}) {
final todo = dataList[index] as TodoModel;
return ListTile(
leading: Checkbox(
value: todo.completed,
onChanged: (_) => _toggleTodo(index),
),
title: Text(
todo.title,
style: TextStyle(
decoration: todo.completed ? TextDecoration.lineThrough : null,
),
),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => _deleteTodo(index),
),
);
}
@override
Future<void> getNetWorkData({required int type}) async {
// 在实际应用中,这里会从网络获取数据
// 本示例中使用本地数据,所以这个方法不需要实现
}
@override
void dispose() {
_textController.dispose();
super.dispose();
}
}
注册路由
在路由配置中添加待办事项列表页面:
dart
// lib/config/router/routes.dart
import 'package:flucli_example/pages/todo_list_page.dart';
class Routes {
static final routes = {
// 其他路由...
'/todo_list': (context) => const TodoListPage(),
};
}
更新主页面
在主页面添加一个按钮,用于导航到待办事项列表页面:
dart
// 在主页面的某个位置添加
ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/todo_list');
},
child: Text('待办事项列表'),
),
使用 base_getx_ui 实现
创建数据模型
数据模型与 base_normal_ui
实现相同:
dart
// lib/models/todo_model.dart
class TodoModel {
final int id;
final String title;
bool completed;
TodoModel({
required this.id,
required this.title,
this.completed = false,
});
TodoModel copyWith({
int? id,
String? title,
bool? completed,
}) {
return TodoModel(
id: id ?? this.id,
title: title ?? this.title,
completed: completed ?? this.completed,
);
}
}
创建控制器
使用 GetX 创建控制器:
dart
// lib/vm/todo_list_controller.dart
import 'package:get/get.dart';
import 'package:flucli_example/common/base_ui/base_getx_ui/base_getx_list_controller.dart';
import 'package:flucli_example/models/todo_model.dart';
class TodoListController extends BaseGetXListController {
final textController = TextEditingController();
@override
void onInit() {
super.onInit();
// 初始化一些示例数据
dataList.value = [
TodoModel(id: 1, title: '学习 Flutter'),
TodoModel(id: 2, title: '学习 FluCli'),
TodoModel(id: 3, title: '学习 base_getx_ui'),
];
// 设置页面状态为成功
pageState.value = PageState.successState;
}
void addTodo() {
if (textController.text.isNotEmpty) {
dataList.add(TodoModel(
id: dataList.length + 1,
title: textController.text,
));
textController.clear();
}
}
void toggleTodo(int index) {
final todo = dataList[index] as TodoModel;
dataList[index] = todo.copyWith(completed: !todo.completed);
}
void deleteTodo(int index) {
dataList.removeAt(index);
}
@override
Future<void> getNetWorkData({required int type}) async {
// 在实际应用中,这里会从网络获取数据
// 本示例中使用本地数据,所以这个方法不需要实现
}
@override
void onClose() {
textController.dispose();
super.onClose();
}
}
创建待办事项列表页面
使用 base_getx_ui
创建待办事项列表页面:
dart
// lib/pages/todo_list_page.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flucli_example/common/base_ui/base_getx_ui/base_getx_list_v.dart';
import 'package:flucli_example/models/todo_model.dart';
import 'package:flucli_example/vm/todo_list_controller.dart';
class TodoListPage extends BaseGetXListV<TodoListController> {
const TodoListPage({Key? key}) : super(key: key);
@override
TodoListController get controller => Get.put(TodoListController());
@override
void configDefault() {
super.configDefault();
appBarTitle = '待办事项';
}
@override
Widget buildSuccessContent() {
return Column(
children: [
_buildAddTodoInput(),
Expanded(
child: Obx(() {
return ListView.builder(
itemCount: controller.dataList.length,
itemBuilder: (context, index) {
return createListItem(
index: index,
dataList: controller.dataList,
);
},
);
}),
),
],
);
}
Widget _buildAddTodoInput() {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: controller.textController,
decoration: InputDecoration(
hintText: '添加新的待办事项',
border: OutlineInputBorder(),
),
),
),
SizedBox(width: 16),
ElevatedButton(
onPressed: controller.addTodo,
child: Text('添加'),
),
],
),
);
}
@override
Widget createListItem({required int index, required List dataList}) {
final todo = dataList[index] as TodoModel;
return ListTile(
leading: Checkbox(
value: todo.completed,
onChanged: (_) => controller.toggleTodo(index),
),
title: Text(
todo.title,
style: TextStyle(
decoration: todo.completed ? TextDecoration.lineThrough : null,
),
),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => controller.deleteTodo(index),
),
);
}
}
注册路由
在 GetX 中注册路由:
dart
// lib/config/router/routes.dart
import 'package:get/get.dart';
import 'package:flucli_example/pages/todo_list_page.dart';
class AppRoutes {
static final routes = [
// 其他路由...
GetPage(
name: '/todo_list',
page: () => const TodoListPage(),
),
];
}
更新主页面
在主页面添加一个按钮,用于导航到待办事项列表页面:
dart
// 在主页面的某个位置添加
ElevatedButton(
onPressed: () {
Get.toNamed('/todo_list');
},
child: Text('待办事项列表'),
),
两种方案的对比
代码结构对比
方面 | base_normal_ui | base_getx_ui |
---|---|---|
状态管理 | 使用 Flutter 原生的 setState | 使用 GetX 的响应式变量 |
代码分离 | UI 和逻辑在同一个类中 | UI 和逻辑分离到不同的类 |
依赖注入 | 手动管理依赖 | 使用 Get.put 自动管理依赖 |
路由管理 | 使用 Navigator | 使用 Get.toNamed |
响应式更新 | 需要手动调用 setState | 自动响应数据变化 |
优缺点分析
base_normal_ui
优点:
- 学习成本低,使用 Flutter 原生 API
- 不依赖第三方库,减少包大小
- 代码逻辑直观,易于理解
缺点:
- UI 和逻辑耦合度高
- 状态管理较为繁琐,需要手动调用 setState
- 大型应用中可能导致代码臃肿
base_getx_ui
优点:
- UI 和逻辑分离,代码结构清晰
- 响应式编程,自动更新 UI
- 内置依赖注入和路由管理
- 适合大型应用开发
缺点:
- 学习成本较高,需要了解 GetX 框架
- 依赖第三方库,增加包大小
- 对 Flutter 原理理解要求较高
如何选择
- 项目规模:小型项目可以选择
base_normal_ui
,大型项目推荐base_getx_ui
- 团队经验:Flutter 新手推荐
base_normal_ui
,有经验的开发者可以选择base_getx_ui
- 性能要求:对性能要求极高的场景,
base_normal_ui
可能更有优势 - 开发效率:追求开发效率,
base_getx_ui
更胜一筹
总结
通过本示例,我们展示了如何使用 FluCli 创建项目,并分别使用 base_normal_ui
和 base_getx_ui
两种状态管理方案实现相同的功能。两种方案各有优缺点,您可以根据项目需求和团队情况选择合适的方案。
无论选择哪种方案,FluCli 都提供了完善的项目结构和基础组件,帮助您快速开发高质量的 Flutter 应用。
提示
想要了解更多关于 FluCli 的信息,请查看 FluCli 官方文档。