社团管理App中的任务列表功能是日常运营的核心模块。作为社团管理者,我经常面临这样的困境:活动策划、物资采购、宣传推广等多项任务需要同时推进,但缺乏有效的可视化工具来跟踪进度。传统的微信群聊或Excel表格难以满足实时协作和状态跟踪的需求。
这个任务列表页面需要解决以下核心问题:
选择Flutter实现这个功能主要基于以下考虑:
我们评估了多种状态管理方案后选择Provider:
最终选择Provider的原因:
dart复制class TaskListPage extends StatefulWidget {
const TaskListPage({super.key});
@override
State<TaskListPage> createState() => _TaskListPageState();
}
class _TaskListPageState extends State<TaskListPage>
with SingleTickerProviderStateMixin {
late TabController _tabController;
@override
void initState() {
super.initState();
_tabController = TabController(length: 3, vsync: this);
}
@override
void dispose() {
_tabController.dispose();
super.dispose();
}
关键点解析:
SingleTickerProviderStateMixin提供动画帧同步,确保Tab切换动画流畅dart复制Widget _buildTaskCard(Task task, AppProvider provider) {
Color priorityColor;
switch (task.priority) {
case 1: priorityColor = Colors.red; break;
case 2: priorityColor = Colors.orange; break;
default: priorityColor = Colors.green;
}
final isOverdue = task.deadline.isBefore(DateTime.now())
&& task.status != '已完成';
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 卡片内容...
],
),
),
);
}
视觉设计原则:
dart复制PopupMenuButton<String>(
onSelected: (value) {
provider.updateTaskStatus(task.id, value);
},
itemBuilder: (context) => [
const PopupMenuItem(value: '待完成', child: Text('待完成')),
const PopupMenuItem(value: '进行中', child: Text('进行中')),
const PopupMenuItem(value: '已完成', child: Text('已完成')),
],
)
交互优化点:
dart复制class Task {
final String id;
final String clubId;
final String title;
final String description;
final String assignee;
final DateTime deadline;
final int priority;
final String status;
Task({
String? id,
required this.clubId,
required this.title,
this.description = '',
required this.assignee,
required this.deadline,
this.priority = 3,
this.status = '待完成',
}) : id = id ?? DateTime.now().millisecondsSinceEpoch.toString();
}
字段设计考量:
dart复制class AppProvider extends ChangeNotifier {
final List<Task> _tasks = [];
List<Task> get tasks => _tasks;
void addTask(Task task) {
_tasks.add(task);
notifyListeners();
}
void updateTaskStatus(String taskId, String status) {
final index = _tasks.indexWhere((t) => t.id == taskId);
if (index != -1) {
_tasks[index] = Task(
id: _tasks[index].id,
clubId: _tasks[index].clubId,
title: _tasks[index].title,
description: _tasks[index].description,
assignee: _tasks[index].assignee,
deadline: _tasks[index].deadline,
priority: _tasks[index].priority,
status: status,
);
notifyListeners();
}
}
}
性能优化技巧:
_tasks列表并通过getter暴露,防止外部修改dart复制void _showAddTaskDialog(BuildContext context) {
final titleController = TextEditingController();
final descController = TextEditingController();
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: const Text('新建任务'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: titleController,
decoration: const InputDecoration(
labelText: '任务标题',
border: OutlineInputBorder()
),
),
const SizedBox(height: 12),
TextField(
controller: descController,
decoration: const InputDecoration(
labelText: '任务描述',
border: OutlineInputBorder()
),
maxLines: 2,
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(ctx),
child: const Text('取消')
),
ElevatedButton(
onPressed: () {
if (titleController.text.isNotEmpty) {
final provider = Provider.of<AppProvider>(
context,
listen: false
);
provider.addTask(Task(
clubId: 'club001',
title: titleController.text,
description: descController.text,
assignee: provider.currentUser.name,
deadline: DateTime.now().add(
const Duration(days: 7)
),
));
Navigator.pop(ctx);
}
},
child: const Text('创建'),
),
],
),
);
}
表单处理最佳实践:
dart复制import 'package:intl/intl.dart';
// 在卡片中显示格式化日期
Text(
'截止: ${DateFormat('MM-dd HH:mm').format(task.deadline)}',
style: TextStyle(
fontSize: 12,
color: isOverdue ? Colors.red : Colors.grey
),
)
日期处理要点:
dart复制ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: tasks.length,
itemBuilder: (context, index) {
final task = tasks[index];
return _buildTaskCard(task, provider);
},
)
优化策略:
问题1:Tab切换卡顿
问题2:状态更新后UI不刷新
问题3:键盘遮挡输入框
在实现这些功能时,我发现Flutter的灵活性真的令人惊喜。通过组合各种Widget,可以快速构建出功能丰富、体验流畅的界面。特别是Hot Reload功能,让UI调整变得非常高效。
一个实用的技巧是:在开发过程中,我习惯为每个组件添加key属性。这不仅能帮助Flutter更高效地更新UI,在遇到一些奇怪的渲染问题时,也更容易定位问题所在。比如给每个任务卡片添加UniqueKey,可以确保状态更新时重建正确。