鸿蒙+flutter 跨平台开发——从0到1打造一款人生清单管理工具
📝 文章摘要: 本文介绍了基于鸿蒙+Flutter的跨平台人生清单管理工具开发实践。该应用采用Flutter 3.6.2实现跨平台UI,结合鸿蒙OS的分布式能力,具有任务管理、分类、进度追踪等核心功能。文章详细阐述了技术选型(鸿蒙+Flutter互补优势)、应用架构(分层设计)、数据模型(Task类实现)和存储服务(TaskStorageService)等关键技术实现。项目采用简洁现代的设计风格
📱 鸿蒙+Flutter 跨平台开发——从0到1打造一款人生清单管理工具
🚀运行效果展示


🌟 前言
在数字化时代,我们每天都面临着无数的待办事项,从工作任务到个人目标,从短期计划到长期梦想。如何高效地管理这些事项,成为了现代人面临的重要挑战。与此同时,跨平台开发技术也在快速发展,为开发者提供了一次编写、多端运行的便利。
技术选型思考
| 技术平台 | 优势 | 劣势 |
|---|---|---|
| 鸿蒙OS | 分布式生态、强大的安全机制、国产自主可控 | 生态相对年轻 |
| Flutter | 跨平台兼容性好、高性能UI渲染、热重载 | 包体积较大 |
为什么选择鸿蒙+Flutter?
- ✅ 互补优势:鸿蒙提供底层安全和分布式能力,Flutter提供优秀的跨平台UI体验
- ✅ 开发效率:一次编写,多端运行,大幅降低开发成本
- ✅ 未来潜力:鸿蒙作为国产操作系统,拥有广阔的发展前景
- ✅ 用户体验:Flutter的Material Design和Cupertino风格,提供原生级别的UI体验
人生清单管理工具的价值
人生清单管理工具,不仅仅是一个简单的待办事项应用,更是一个帮助用户实现人生目标的助手。它可以:
- 🎯 帮助用户清晰地规划人生目标
- 📊 可视化展示任务进度
- ⏰ 智能提醒重要事项
- 💪 激励用户坚持完成目标
🎮 应用介绍
应用定位
人生清单管理工具是一款基于鸿蒙+Flutter开发的跨平台应用,旨在帮助用户记录、管理和实现人生中的各种目标和梦想。
核心功能
| 功能模块 | 主要功能 |
|---|---|
| 📝 任务管理 | 添加、编辑、删除任务 |
| 🏷️ 任务分类 | 支持按优先级、状态、标签分类 |
| 📅 时间管理 | 支持设置截止日期、提醒 |
| 📊 进度追踪 | 可视化展示任务完成进度 |
| 🔄 状态切换 | 支持任务状态的切换(待办、进行中、已完成) |
| 📤 数据同步 | 支持本地存储(未来可扩展到云同步) |
应用界面设计
应用采用了简洁、现代的设计风格,主要包含以下页面:
- 任务列表页:展示所有任务,支持分类和筛选
- 任务详情页:展示任务的详细信息
- 任务添加/编辑页:用于添加新任务或编辑现有任务
- 统计分析页:展示任务完成情况的统计数据
🏗️ 技术架构
应用架构图
项目结构
lib/
├── models/ # 数据模型
│ └── task.dart # 任务数据模型
├── services/ # 业务逻辑服务
│ └── task_storage_service.dart # 任务存储服务
├── pages/ # 页面组件
│ ├── task_list_page.dart # 任务列表页
│ └── task_add_edit_page.dart # 任务添加/编辑页
├── widgets/ # 通用组件
│ └── task_item.dart # 任务项组件
└── main.dart # 应用入口
核心技术栈
| 技术 | 版本 | 用途 |
|---|---|---|
| Flutter | 3.6.2 | 跨平台UI框架 |
| Dart | 3.6.2 | 开发语言 |
| intl | 0.19.0 | 日期时间格式化 |
| uuid | 4.4.0 | 生成唯一标识符 |
| shared_preferences | 2.3.2 | 本地存储(备选方案) |
🔧 核心功能实现
1. 任务数据模型设计
import 'dart:convert';
import 'package:intl/intl.dart';
/// 任务状态枚举
enum TaskStatus {
todo, // 待办
inProgress, // 进行中
completed, // 已完成
}
/// 任务优先级枚举
enum TaskPriority {
low,
medium,
high,
}
/// 任务数据模型
class Task {
final String id;
final String title;
final String description;
final DateTime createdAt;
final TaskStatus status;
final TaskPriority priority;
final DateTime? dueDate;
Task({
required this.id,
required this.title,
required this.description,
required this.createdAt,
this.status = TaskStatus.todo,
this.priority = TaskPriority.medium,
this.dueDate,
});
// 从JSON创建Task实例
factory Task.fromJson(Map<String, dynamic> json) {
return Task(
id: json['id'],
title: json['title'],
description: json['description'],
createdAt: DateTime.parse(json['createdAt']),
status: TaskStatus.values[json['status']],
priority: TaskPriority.values[json['priority']],
dueDate: json['dueDate'] != null ? DateTime.parse(json['dueDate']) : null,
);
}
// 转换为JSON格式
Map<String, dynamic> toJson() {
return {
'id': id,
'title': title,
'description': description,
'createdAt': createdAt.toIso8601String(),
'status': status.index,
'priority': priority.index,
'dueDate': dueDate?.toIso8601String(),
};
}
// 复制方法,用于更新任务
Task copyWith({
String? id,
String? title,
String? description,
DateTime? createdAt,
TaskStatus? status,
TaskPriority? priority,
DateTime? dueDate,
}) {
return Task(
id: id ?? this.id,
title: title ?? this.title,
description: description ?? this.description,
createdAt: createdAt ?? this.createdAt,
status: status ?? this.status,
priority: priority ?? this.priority,
dueDate: dueDate ?? this.dueDate,
);
}
}
2. 任务存储服务
import 'dart:convert';
import '../models/task.dart';
/// 任务存储服务
class TaskStorageService {
/// 内存存储的任务列表
static List<Task> _memoryTasks = [];
/// 保存任务列表
Future<void> saveTasks(List<Task> tasks) async {
_memoryTasks = tasks;
}
/// 加载任务列表
Future<List<Task>> loadTasks() async {
return _memoryTasks;
}
/// 添加任务
Future<void> addTask(Task task) async {
final tasks = await loadTasks();
tasks.add(task);
await saveTasks(tasks);
}
/// 更新任务
Future<void> updateTask(Task task) async {
final tasks = await loadTasks();
final index = tasks.indexWhere((t) => t.id == task.id);
if (index != -1) {
tasks[index] = task;
await saveTasks(tasks);
}
}
/// 删除任务
Future<void> deleteTask(String taskId) async {
final tasks = await loadTasks();
tasks.removeWhere((t) => t.id == taskId);
await saveTasks(tasks);
}
/// 切换任务状态
Future<void> toggleTaskStatus(String taskId, TaskStatus newStatus) async {
final tasks = await loadTasks();
final index = tasks.indexWhere((t) => t.id == taskId);
if (index != -1) {
tasks[index] = tasks[index].copyWith(status: newStatus);
await saveTasks(tasks);
}
}
}
3. 任务列表页面
import 'package:flutter/material.dart';
import '../models/task.dart';
import '../services/task_storage_service.dart';
import 'task_add_edit_page.dart';
/// 任务列表页面
class TaskListPage extends StatefulWidget {
const TaskListPage({Key? key}) : super(key: key);
State<TaskListPage> createState() => _TaskListPageState();
}
class _TaskListPageState extends State<TaskListPage> {
List<Task> _tasks = [];
bool _isLoading = true;
final _taskStorageService = TaskStorageService();
void initState() {
super.initState();
_loadTasks();
}
/// 加载任务列表
Future<void> _loadTasks() async {
setState(() {
_isLoading = true;
});
try {
final tasks = await _taskStorageService.loadTasks();
setState(() {
_tasks = tasks;
});
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('加载任务失败: $e')),
);
} finally {
setState(() {
_isLoading = false;
});
}
}
/// 导航到添加任务页面
void _navigateToAddTask() async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => const TaskAddEditPage()),
);
if (result == true) {
_loadTasks();
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('人生清单'),
centerTitle: true,
),
body: _isLoading
? const Center(child: CircularProgressIndicator())
: _buildTaskList(),
floatingActionButton: FloatingActionButton(
onPressed: _navigateToAddTask,
tooltip: '添加任务',
child: const Icon(Icons.add),
),
);
}
/// 构建任务列表
Widget _buildTaskList() {
if (_tasks.isEmpty) {
return const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.task_alt, size: 64, color: Colors.grey),
SizedBox(height: 16),
Text('还没有任务', style: TextStyle(fontSize: 18, color: Colors.grey)),
SizedBox(height: 8),
Text('点击右下角按钮添加第一个任务', style: TextStyle(fontSize: 14, color: Colors.grey)),
],
),
);
}
return ListView.builder(
itemCount: _tasks.length,
padding: const EdgeInsets.all(8.0),
itemBuilder: (context, index) {
final task = _tasks[index];
return TaskItem(
task: task,
onStatusChange: (status) => _handleStatusChange(task.id, status),
onEdit: () => _navigateToEditTask(task),
onDelete: () => _handleDeleteTask(task.id),
);
},
);
}
// 其他辅助方法...
}
4. 任务添加/编辑页面
import 'package:flutter/material.dart';
import 'package:uuid/uuid.dart';
import '../models/task.dart';
import '../services/task_storage_service.dart';
/// 任务添加/编辑页面
class TaskAddEditPage extends StatefulWidget {
final Task? task;
const TaskAddEditPage({Key? key, this.task}) : super(key: key);
State<TaskAddEditPage> createState() => _TaskAddEditPageState();
}
class _TaskAddEditPageState extends State<TaskAddEditPage> {
final _formKey = GlobalKey<FormState>();
final _titleController = TextEditingController();
final _descriptionController = TextEditingController();
TaskPriority _priority = TaskPriority.medium;
DateTime? _dueDate;
final _taskStorageService = TaskStorageService();
void initState() {
super.initState();
if (widget.task != null) {
_titleController.text = widget.task!.title;
_descriptionController.text = widget.task!.description;
_priority = widget.task!.priority;
_dueDate = widget.task!.dueDate;
}
}
/// 保存任务
Future<void> _saveTask() async {
if (_formKey.currentState!.validate()) {
FocusScope.of(context).unfocus();
try {
final task = widget.task != null
? widget.task!.copyWith(
title: _titleController.text,
description: _descriptionController.text,
priority: _priority,
dueDate: _dueDate,
)
: Task(
id: const Uuid().v4(),
title: _titleController.text,
description: _descriptionController.text,
createdAt: DateTime.now(),
priority: _priority,
dueDate: _dueDate,
);
if (widget.task != null) {
await _taskStorageService.updateTask(task);
} else {
await _taskStorageService.addTask(task);
}
Navigator.pop(context, true);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('保存任务失败: $e')),
);
}
}
}
Widget build(BuildContext context) {
final isEditing = widget.task != null;
return Scaffold(
appBar: AppBar(
title: Text(isEditing ? '编辑任务' : '添加任务'),
centerTitle: true,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(20.0),
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 任务标题输入
TextFormField(
controller: _titleController,
decoration: const InputDecoration(
labelText: '任务标题',
hintText: '请输入任务标题',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.title),
),
validator: (value) {
if (value == null || value.isEmpty) {
return '请输入任务标题';
}
return null;
},
),
const SizedBox(height: 16),
// 任务描述输入
TextFormField(
controller: _descriptionController,
decoration: const InputDecoration(
labelText: '任务描述',
hintText: '请输入任务描述',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.description),
),
maxLines: 4,
),
const SizedBox(height: 20),
// 优先级选择
_buildPrioritySelector(),
const SizedBox(height: 20),
// 截止日期选择
_buildDueDateSelector(),
const SizedBox(height: 30),
// 保存按钮
ElevatedButton(
onPressed: _saveTask,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
textStyle: const TextStyle(fontSize: 18),
),
child: Text(isEditing ? '更新任务' : '添加任务'),
),
],
),
),
),
);
}
// 其他辅助方法...
}
📊 流程图设计
任务添加流程图
任务状态流转图
🔍 核心功能详解
1. 任务优先级管理
应用支持三种优先级:低、中、高,通过不同的颜色进行区分:
- 🔴 高优先级:红色
- 🟡 中优先级:黄色
- 🟢 低优先级:绿色
/// 获取优先级对应的颜色
Color getPriorityColor(TaskPriority priority) {
switch (priority) {
case TaskPriority.low:
return Colors.green;
case TaskPriority.medium:
return Colors.yellow;
case TaskPriority.high:
return Colors.red;
}
}
2. 截止日期提醒
应用会自动检查任务的截止日期,并在截止日期临近时显示提醒:
- ⚠️ 截止日期当天:显示黄色提醒
- 🔴 已过期:显示红色提醒
- ✅ 未过期:显示正常颜色
/// 获取截止日期显示样式
TextStyle getDueDateStyle(DateTime? dueDate) {
if (dueDate == null) {
return const TextStyle(color: Colors.grey);
}
final now = DateTime.now();
final difference = dueDate.difference(now);
if (difference.isNegative) {
// 已过期
return const TextStyle(color: Colors.red, fontWeight: FontWeight.bold);
} else if (difference.inDays <= 1) {
// 即将过期
return const TextStyle(color: Colors.orange, fontWeight: FontWeight.bold);
} else {
// 未过期
return const TextStyle(color: Colors.grey);
}
}
3. 任务状态管理
应用支持三种任务状态:
- 📝 待办:任务尚未开始
- 🔄 进行中:任务正在执行
- ✅ 已完成:任务已经完成
/// 获取状态对应的图标
Icon getStatusIcon(TaskStatus status) {
switch (status) {
case TaskStatus.todo:
return const Icon(Icons.radio_button_unchecked);
case TaskStatus.inProgress:
return const Icon(Icons.pending);
case TaskStatus.completed:
return const Icon(Icons.check_circle);
}
}
🎉 总结与展望
项目成果
通过本次开发,我们成功打造了一款功能完整的人生清单管理工具,具有以下特点:
- ✅ 跨平台兼容:支持鸿蒙及其他Flutter平台
- ✅ 功能完整:包含任务管理的核心功能
- ✅ UI美观:采用现代简洁的设计风格
- ✅ 性能优良:流畅的用户体验
- ✅ 易于扩展:模块化的代码结构
未来规划
- 云同步功能:支持多设备数据同步
- 数据分析功能:提供任务完成情况的数据分析和可视化
- 社交分享功能:支持任务的分享和协作
- 语音输入功能:支持语音添加任务
- 智能推荐功能:根据用户习惯推荐任务管理策略
- 鸿蒙分布式特性:充分利用鸿蒙的分布式能力,实现多设备协同
💡 技术感悟
鸿蒙+Flutter的组合,为跨平台开发提供了新的可能性。鸿蒙的安全机制和分布式能力,结合Flutter的优秀UI体验,能够打造出既安全又易用的跨平台应用。
在开发过程中,我们遇到了一些挑战,特别是在平台兼容性方面,但通过合理的设计和适配,最终成功实现了目标。这也让我们深刻体会到,跨平台开发不仅仅是技术的堆叠,更是需要对不同平台的深入理解和合理适配。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐




所有评论(0)