在这里插入图片描述

待办事项管理是提升工作效率的重要工具。一个好的待办事项功能应该让用户能够快速添加任务、标记完成状态,并且能够按优先级和分类来组织任务。今天我来分享一下如何实现这个功能。

功能设计

在设计待办事项功能时,我主要考虑了以下几个方面:

首先是任务的展示,我在顶部放了一个统计区域,显示全部任务数、已完成数和未完成数,让用户对自己的任务情况一目了然。

其次是任务的管理,每个任务都可以标记完成状态、设置优先级、添加分类。用户可以通过滑动删除任务,这种交互方式很符合移动端的使用习惯。

最后是任务的添加,点击右上角的加号按钮就能快速添加新任务,整个流程非常简洁。

页面结构实现

让我先看看整体的代码结构:

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

class TodoListPage extends StatefulWidget {
  const TodoListPage({super.key});

  
  State<TodoListPage> createState() => _TodoListPageState();
}

class _TodoListPageState extends State<TodoListPage> {
  final List<Map<String, dynamic>> todos = [
    {'title': '完成项目报告', 'completed': false, 'priority': 'high', 'category': '工作'},
    {'title': '去超市买菜', 'completed': false, 'priority': 'medium', 'category': '生活'},
    {'title': '健身房锻炼', 'completed': true, 'priority': 'low', 'category': '健康'},
    {'title': '阅读30分钟', 'completed': false, 'priority': 'medium', 'category': '学习'},
  ];

  
  Widget build(BuildContext context) {
    final completedCount = todos.where((t) => t['completed']).length;
    
    return Scaffold(
      appBar: AppBar(
        title: const Text('待办事项'),
        actions: [
          IconButton(
            icon: const Icon(Icons.add),
            onPressed: _showAddDialog,
          ),
        ],
      ),
      body: Column(
        children: [
          Container(
            padding: EdgeInsets.all(20.w),
            color: Colors.blue[50],
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                _buildStatItem('全部', '${todos.length}', Colors.blue),
                _buildStatItem('已完成', '$completedCount', Colors.green),
                _buildStatItem('未完成', '${todos.length - completedCount}', Colors.orange),
              ],
            ),
          ),
          Expanded(
            child: ListView.builder(
              padding: EdgeInsets.all(16.w),
              itemCount: todos.length,
              itemBuilder: (context, index) {
                return _buildTodoCard(todos[index], index);
              },
            ),
          ),
        ],
      ),
    );
  }
}

这个页面使用了StatefulWidget,因为需要管理任务列表的状态。顶部是统计区域,下面是任务列表。

统计区域设计

统计区域让用户能够快速了解任务的整体情况:

Widget _buildStatItem(String label, String value, Color color) {
  return Column(
    children: [
      Text(
        value,
        style: TextStyle(
          fontSize: 24.sp,
          fontWeight: FontWeight.bold,
          color: color,
        ),
      ),
      SizedBox(height: 4.h),
      Text(label, style: TextStyle(fontSize: 12.sp, color: Colors.grey)),
    ],
  );
}

每个统计项都包含一个数字和一个标签。数字用大号字体和彩色显示,非常醒目。全部任务用蓝色,已完成用绿色,未完成用橙色,这种颜色区分让信息更加清晰。

任务卡片实现

任务卡片是整个功能的核心,它需要展示任务的所有信息并支持交互:

Widget _buildTodoCard(Map<String, dynamic> todo, int index) {
  Color priorityColor = Colors.grey;
  if (todo['priority'] == 'high') priorityColor = Colors.red;
  if (todo['priority'] == 'medium') priorityColor = Colors.orange;

  return Dismissible(
    key: Key(todo['title']),
    background: Container(
      color: Colors.red,
      alignment: Alignment.centerRight,
      padding: EdgeInsets.only(right: 20.w),
      child: const Icon(Icons.delete, color: Colors.white),
    ),
    direction: DismissDirection.endToStart,
    onDismissed: (direction) {
      setState(() {
        todos.removeAt(index);
      });
    },
    child: Container(
      margin: EdgeInsets.only(bottom: 12.h),
      padding: EdgeInsets.all(16.w),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(12.r),
      ),
      child: Row(
        children: [
          Checkbox(
            value: todo['completed'],
            onChanged: (value) {
              setState(() {
                todos[index]['completed'] = value;
              });
            },
          ),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  todo['title'],
                  style: TextStyle(
                    fontSize: 14.sp,
                    decoration: todo['completed'] ? TextDecoration.lineThrough : null,
                  ),
                ),
                SizedBox(height: 4.h),
                Text(
                  todo['category'],
                  style: TextStyle(fontSize: 12.sp, color: Colors.grey),
                ),
              ],
            ),
          ),
          Container(
            width: 8.w,
            height: 8.w,
            decoration: BoxDecoration(
              color: priorityColor,
              shape: BoxShape.circle,
            ),
          ),
        ],
      ),
    ),
  );
}

这个任务卡片的设计很有意思。我使用了Dismissible组件来实现滑动删除功能,用户向左滑动任务卡片就能看到红色的删除背景,继续滑动就会删除任务。

每个任务卡片包含一个复选框、任务标题、分类标签和优先级指示器。复选框用来标记任务是否完成,当任务完成时,标题会显示删除线效果。

优先级用一个小圆点来表示,高优先级是红色,中优先级是橙色,低优先级是灰色。这种设计既简洁又直观。

添加任务对话框

用户需要能够快速添加新任务,我实现了一个简单的对话框:

void _showAddDialog() {
  showDialog(
    context: context,
    builder: (context) => AlertDialog(
      title: const Text('添加待办'),
      content: TextField(
        decoration: const InputDecoration(
          hintText: '输入待办事项',
          border: OutlineInputBorder(),
        ),
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: const Text('取消'),
        ),
        TextButton(
          onPressed: () {
            Navigator.pop(context);
            ScaffoldMessenger.of(context).showSnackBar(
              const SnackBar(content: Text('添加成功')),
            );
          },
          child: const Text('添加'),
        ),
      ],
    ),
  );
}

这个对话框很简单,只有一个输入框和两个按钮。在实际应用中,你可以添加更多的选项,比如选择优先级、设置截止日期、添加备注等。

数据模型设计

为了更好地管理任务数据,我建议定义一个Todo模型:

class Todo {
  final String id;
  final String title;
  final bool completed;
  final String priority; // 'high', 'medium', 'low'
  final String category;
  final DateTime? dueDate;
  final String? note;
  
  Todo({
    required this.id,
    required this.title,
    this.completed = false,
    this.priority = 'medium',
    required this.category,
    this.dueDate,
    this.note,
  });
  
  Todo copyWith({
    String? id,
    String? title,
    bool? completed,
    String? priority,
    String? category,
    DateTime? dueDate,
    String? note,
  }) {
    return Todo(
      id: id ?? this.id,
      title: title ?? this.title,
      completed: completed ?? this.completed,
      priority: priority ?? this.priority,
      category: category ?? this.category,
      dueDate: dueDate ?? this.dueDate,
      note: note ?? this.note,
    );
  }
  
  Map<String, dynamic> toJson() => {
    'id': id,
    'title': title,
    'completed': completed,
    'priority': priority,
    'category': category,
    'dueDate': dueDate?.toIso8601String(),
    'note': note,
  };
  
  factory Todo.fromJson(Map<String, dynamic> json) => Todo(
    id: json['id'],
    title: json['title'],
    completed: json['completed'],
    priority: json['priority'],
    category: json['category'],
    dueDate: json['dueDate'] != null ? DateTime.parse(json['dueDate']) : null,
    note: json['note'],
  );
}

这个模型包含了任务的所有必要信息,并提供了copyWith方法来方便地更新任务属性。

数据持久化

任务数据需要持久化存储,我建议使用SQLite或SharedPreferences:

import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';

class TodoService {
  static const String _keyTodos = 'todos';
  
  // 保存任务列表
  static Future<void> saveTodos(List<Todo> todos) async {
    final prefs = await SharedPreferences.getInstance();
    final jsonList = todos.map((t) => t.toJson()).toList();
    await prefs.setString(_keyTodos, jsonEncode(jsonList));
  }
  
  // 获取任务列表
  static Future<List<Todo>> getTodos() async {
    final prefs = await SharedPreferences.getInstance();
    final jsonString = prefs.getString(_keyTodos);
    if (jsonString == null) return [];
    
    final jsonList = jsonDecode(jsonString) as List;
    return jsonList.map((json) => Todo.fromJson(json)).toList();
  }
  
  // 添加任务
  static Future<void> addTodo(Todo todo) async {
    final todos = await getTodos();
    todos.add(todo);
    await saveTodos(todos);
  }
  
  // 更新任务
  static Future<void> updateTodo(Todo todo) async {
    final todos = await getTodos();
    final index = todos.indexWhere((t) => t.id == todo.id);
    if (index != -1) {
      todos[index] = todo;
      await saveTodos(todos);
    }
  }
  
  // 删除任务
  static Future<void> deleteTodo(String id) async {
    final todos = await getTodos();
    todos.removeWhere((t) => t.id == id);
    await saveTodos(todos);
  }
}

这个服务类提供了完整的CRUD操作,可以方便地管理任务数据。

任务排序和筛选

用户可能需要按不同的方式查看任务,我们可以添加排序和筛选功能:

class TodoController {
  List<Todo> _todos = [];
  
  // 按优先级排序
  List<Todo> sortByPriority() {
    final priorityOrder = {'high': 0, 'medium': 1, 'low': 2};
    return _todos..sort((a, b) => 
      priorityOrder[a.priority]!.compareTo(priorityOrder[b.priority]!)
    );
  }
  
  // 按截止日期排序
  List<Todo> sortByDueDate() {
    return _todos..sort((a, b) {
      if (a.dueDate == null) return 1;
      if (b.dueDate == null) return -1;
      return a.dueDate!.compareTo(b.dueDate!);
    });
  }
  
  // 筛选未完成的任务
  List<Todo> getIncompleteTodos() {
    return _todos.where((t) => !t.completed).toList();
  }
  
  // 按分类筛选
  List<Todo> getTodosByCategory(String category) {
    return _todos.where((t) => t.category == category).toList();
  }
  
  // 搜索任务
  List<Todo> searchTodos(String keyword) {
    return _todos.where((t) => 
      t.title.toLowerCase().contains(keyword.toLowerCase())
    ).toList();
  }
}

这些方法让用户能够更灵活地管理和查看任务。

任务提醒功能

对于有截止日期的任务,我们可以添加提醒功能:

import 'package:flutter_local_notifications/flutter_local_notifications.dart';

class TodoReminderService {
  static final FlutterLocalNotificationsPlugin _notifications = 
      FlutterLocalNotificationsPlugin();
  
  static Future<void> scheduleReminder(Todo todo) async {
    if (todo.dueDate == null) return;
    
    // 在截止日期前一天提醒
    final reminderTime = todo.dueDate!.subtract(const Duration(days: 1));
    
    await _notifications.zonedSchedule(
      todo.id.hashCode,
      '任务提醒',
      '明天要完成:${todo.title}',
      TZDateTime.from(reminderTime, local),
      const NotificationDetails(
        android: AndroidNotificationDetails(
          'todo_reminder',
          '任务提醒',
          channelDescription: '提醒您完成待办任务',
          importance: Importance.high,
        ),
      ),
      uiLocalNotificationDateInterpretation: 
          UILocalNotificationDateInterpretation.absoluteTime,
    );
  }
}

这个服务可以在任务截止日期前发送提醒通知。

性能优化

当任务数量很多时,需要注意性能优化:

第一,使用分页加载。不要一次性加载所有任务,而是先加载最近的50条,用户滚动到底部时再加载更多。

第二,使用虚拟滚动。ListView.builder本身就支持虚拟滚动,只渲染可见区域的任务。

第三,优化setState的调用。不要在每次数据变化时都调用setState,可以使用防抖动机制。

扩展功能

基于这个待办事项功能,还可以添加很多实用的特性:

比如添加子任务功能,让用户可以把大任务分解成多个小任务。

或者添加任务模板,用户可以保存常用的任务模板,下次直接使用。

还可以加入番茄钟功能,帮助用户专注完成任务。

另外,可以添加任务统计,展示用户的完成率、效率趋势等数据。

总结

待办事项管理是一个看似简单但很实用的功能。通过合理的设计和实现,它能够真正帮助用户提升工作效率。

在开发过程中,我特别注重用户体验。滑动删除、复选框标记、优先级指示,这些细节都让功能更加易用。同时,数据的持久化和提醒功能也保证了功能的实用性。

希望这篇文章能帮助你实现一个优秀的待办事项管理功能。记住,好的工具不仅要功能完善,更要简单易用。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐