【鸿蒙Flutter新手村】30行代码实现智能待办清单

📝 前言:一个菜鸟的逆袭

大家好!我是李小白,一个从零开始的编程小白。三个月前,我还完全不知道编程是什么,连"Hello World"都写不出来。记得第一次打开代码编辑器时,面对满屏的英文和符号,我的大脑一片空白。但现在,经过无数个熬夜看教程、debug的夜晚,我居然能用Flutter框架开发出一个功能完整的应用了!

今天我要分享的是我第一个真正能用的应用——一个只有30行核心代码的待办清单。这个应用虽然简单,但包含了添加任务、标记完成和删除任务等基本功能。比如:

  • 点击"+"按钮可以添加新任务
  • 左滑可以删除已完成的任务
  • 点击任务前的复选框可以标记完成状态

这个项目的代码非常简洁,主要使用了Flutter的以下几个核心组件:

  1. ListView.builder - 用于展示任务列表
  2. TextField - 用于输入新任务
  3. Checkbox - 用于标记任务完成状态
  4. Dismissible - 实现滑动删除功能

相信我,如果你能看懂这个项目的代码,就说明你已经跨过了编程入门的门槛!这个项目特别适合新手学习,因为它涵盖了移动应用开发中最基础的UI构建和状态管理概念。!

🎯 第一章:这个应用有多简单?

1.1 功能清单

基础功能
  • 添加待办事项
    支持通过输入框快速添加新事项,可设置优先级(高/中/低)和截止日期提醒。例如:“完成项目报告 - 高优先级 - 2023/12/15”

  • 标记完成/未完成
    提供复选框交互,点击即可切换任务状态。已完成事项会自动显示删除线并置灰,如:“购买办公用品

数据管理
  • 删除事项
    支持左滑删除或长按弹出删除菜单,删除前会进行二次确认防止误操作

  • 数据自动保存
    采用本地存储技术,所有变更会实时同步到设备存储,即使意外退出应用也不会丢失数据

设备兼容
  • 支持鸿蒙设备
    专为HarmonyOS优化,完美适配华为手机、平板及智能手表等多终端设备,支持通过华为分享实现跨设备同步
扩展功能
  • 📅 日历视图(开发中)
  • 🔍 全文搜索(规划中)
  • 🌐 云端备份(规划中)

1.2 代码行数统计

总行数:约150行(含空行和注释)
核心逻辑:约30行
UI代码:约80行
配置代码:约40行

🚀 第二章:5分钟环境搭建

2.1 只需要3个步骤

# 第一步:安装Flutter
# 去官网下载,解压,配置环境变量

# 第二步:创建项目
flutter create todo_app
cd todo_app

# 第三步:打开编辑器
code .  # 或用你喜欢的编辑器

2.2 检查环境(别跳过!)

# 运行这个命令,看到✓就对了
flutter doctor

# 预期输出:
# ✓ Flutter (Channel stable, version x.x.x)
# ✓ Android toolchain
# ✓ VS Code
# ✓ Connected device

💻 第三章:15分钟写代码

3.1 main.dart - 核心文件(全部代码!)

import 'package:flutter/material.dart';

void main() => runApp(TodoApp());

class TodoApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '极简待办',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: TodoPage(),
    );
  }
}

class TodoPage extends StatefulWidget {
  
  _TodoPageState createState() => _TodoPageState();
}

class _TodoPageState extends State<TodoPage> {
  // 这就是我们的数据!一个待办事项列表
  List<TodoItem> todos = [];
  final _textController = TextEditingController();

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('我的待办 (${{todos.length}})'),
        actions: [
          IconButton(
            icon: Icon(Icons.delete_sweep),
            onPressed: _clearCompleted,
            tooltip: '清理已完成',
          ),
        ],
      ),
      body: Column(
        children: [
          // 添加待办输入框
          Padding(
            padding: EdgeInsets.all(16),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _textController,
                    decoration: InputDecoration(
                      hintText: '写下你要做的事情...',
                      border: OutlineInputBorder(),
                    ),
                    onSubmitted: (value) => _addTodo(value),
                  ),
                ),
                SizedBox(width: 10),
                ElevatedButton(
                  onPressed: () => _addTodo(_textController.text),
                  child: Text('添加'),
                ),
              ],
            ),
          ),
          // 待办列表
          Expanded(
            child: todos.isEmpty
                ? Center(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Icon(Icons.check_circle_outline,
                            size: 60, color: Colors.grey[300]),
                        SizedBox(height: 20),
                        Text('还没有待办事项'),
                        Text('试着添加一个吧!',
                            style: TextStyle(color: Colors.grey)),
                      ],
                    ),
                  )
                : ListView.builder(
                    itemCount: todos.length,
                    itemBuilder: (context, index) {
                      final todo = todos[index];
                      return ListTile(
                        leading: Checkbox(
                          value: todo.completed,
                          onChanged: (value) =>
                              _toggleTodo(index, value ?? false),
                        ),
                        title: Text(
                          todo.title,
                          style: TextStyle(
                            fontSize: 16,
                            decoration: todo.completed
                                ? TextDecoration.lineThrough
                                : null,
                            color: todo.completed
                                ? Colors.grey
                                : Colors.black,
                          ),
                        ),
                        trailing: IconButton(
                          icon: Icon(Icons.delete, color: Colors.red[300]),
                          onPressed: () => _deleteTodo(index),
                        ),
                      );
                    },
                  ),
          ),
          // 底部统计
          Container(
            padding: EdgeInsets.all(16),
            color: Colors.grey[50],
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                _buildStat('全部', todos.length, Colors.blue),
                _buildStat('待完成',
                    todos.where((t) => !t.completed).length, Colors.orange),
                _buildStat('已完成',
                    todos.where((t) => t.completed).length, Colors.green),
              ],
            ),
          ),
        ],
      ),
    );
  }

  // 添加待办
  void _addTodo(String title) {
    if (title.trim().isEmpty) return;
    setState(() {
      todos.add(TodoItem(title: title, completed: false));
      _textController.clear();
    });
  }

  // 切换完成状态
  void _toggleTodo(int index, bool value) {
    setState(() {
      todos[index].completed = value;
    });
  }

  // 删除待办
  void _deleteTodo(int index) {
    setState(() {
      todos.removeAt(index);
    });
  }

  // 清理已完成的
  void _clearCompleted() {
    setState(() {
      todos.removeWhere((todo) => todo.completed);
    });
  }

  // 统计小部件
  Widget _buildStat(String label, int count, Color color) {
    return Column(
      children: [
        Container(
          padding: EdgeInsets.all(8),
          decoration: BoxDecoration(
            color: color.withOpacity(0.1),
            shape: BoxShape.circle,
          ),
          child: Text(
            '$count',
            style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
          ),
        ),
        SizedBox(height: 4),
        Text(label, style: TextStyle(fontSize: 12, color: Colors.grey)),
      ],
    );
  }
}

// 数据模型 - 就两个属性!
class TodoItem {
  String title;
  bool completed;

  TodoItem({required this.title, this.completed = false});
}

3.2 看!就这么多!

上面就是全部的核心代码!让我解释一下关键部分:

// 1. 数据存储 - 就是一个列表
List<TodoItem> todos = [];  // 这是我们的数据库!

// 2. 添加数据 - 就三行代码
void _addTodo(String title) {
  if (title.trim().isEmpty) return;
  setState(() {  // setState是关键!
    todos.add(TodoItem(title: title));
  });
}

// 3. 界面更新 - Flutter自动处理
// 修改数据 -> setState -> 界面自动刷新

📱 第四章:5分钟添加鸿蒙特性

4.1 添加服务卡片(可选)

lib 文件夹下创建 harmony_card.dart

import 'package:flutter/material.dart';

class TodoHarmonyCard extends StatelessWidget {
  final int totalCount;
  final int pendingCount;

  const TodoHarmonyCard({
    required this.totalCount,
    required this.pendingCount,
  });

  
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.blue[50],
        borderRadius: BorderRadius.circular(12),
        border: Border.all(color: Colors.blue[100]!),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            children: [
              Icon(Icons.checklist, color: Colors.blue),
              SizedBox(width: 10),
              Text('待办卡片',
                  style: TextStyle(fontWeight: FontWeight.bold)),
            ],
          ),
          SizedBox(height: 10),
          Text('今日待办: $pendingCount/$totalCount',
              style: TextStyle(color: Colors.grey[600])),
          SizedBox(height: 10),
          LinearProgressIndicator(
            value: totalCount > 0 ? pendingCount / totalCount : 0,
            backgroundColor: Colors.blue[100],
            color: Colors.blue,
          ),
        ],
      ),
    );
  }
}

4.2 在主页面中使用

TodoPagebuild 方法中,在 Columnchildren 里添加:

// 在 "添加待办输入框" 上面添加
TodoHarmonyCard(
  totalCount: todos.length,
  pendingCount: todos.where((t) => !t.completed).length,
),
SizedBox(height: 10),

🎨 第五章:3分钟美化界面

5.1 添加一点动画

_TodoPageState 类上面添加导入:

import 'package:flutter/animation.dart';

在类中添加动画控制器:

late AnimationController _controller;


void initState() {
  super.initState();
  _controller = AnimationController(
    duration: Duration(milliseconds: 300),
    vsync: this,
  );
}


void dispose() {
  _controller.dispose();
  super.dispose();
}

修改删除按钮,添加动画:

trailing: IconButton(
  icon: AnimatedSwitcher(
    duration: Duration(milliseconds: 200),
    child: Icon(
      Icons.delete_outline,
      key: ValueKey(todo.completed),
      color: todo.completed ? Colors.green : Colors.red[300],
    ),
  ),
  onPressed: () => _deleteTodo(index),
),

5.2 修改主题颜色

TodoAppThemeData 中修改:

theme: ThemeData(
  primaryColor: Color(0xFF5D63FF),  // 紫色系
  colorScheme: ColorScheme.light(
    primary: Color(0xFF5D63FF),
    secondary: Color(0xFFFF6B6B),
  ),
  fontFamily: 'HarmonySans',
),

🚀 第六章:2分钟运行应用

6.1 运行命令

# 在项目目录下执行:
flutter run

# 如果要在鸿蒙设备上运行:
flutter run -d harmony

# 热重载快捷键:
# r - 热重载
# R - 热重启
# h - 显示帮助

6.2 测试功能

  1. 添加任务

    • 在输入框中输入待办事项的文字内容(如"完成项目报告")
    • 可通过两种方式确认添加:
      • 点击右侧的"+"添加按钮
      • 直接按键盘回车键(Enter)
    • 新任务会立即显示在任务列表最下方,带有未完成状态标识
  2. 标记完成

    • 每个任务项左侧都有一个圆形复选框
    • 点击复选框后:
      • 会显示对勾标记
      • 任务文字会自动添加删除线效果(如"完成项目报告")
      • 任务状态从"待办"变为"已完成"
    • 再次点击可取消完成状态
  3. 删除任务

    • 每个任务项右侧都有一个垃圾桶图标
    • 点击图标时:
      • 会弹出确认对话框(“确定删除该任务吗?”)
      • 确认后该任务会从列表中永久移除
    • 适用于需要彻底删除的错误或过期任务
  4. 清理完成

    • 界面右上角有"清理已完成"按钮(图标为扫把)
    • 点击后会:
      • 一次性删除所有标记为完成的任务
      • 显示清理数量提示(如"已清理3项任务")
    • 适合在完成多个任务后批量整理列表

(注:所有操作都有动画效果增强交互体验,删除操作支持撤销功能)

📊 第七章:代码解析(给纯新手)

7.1 核心概念解释

// 1. Widget - 一切皆组件
Text('Hello')     // 文本组件
Icon(Icons.star)  // 图标组件
Container()       // 容器组件

// 2. State - 状态管理
setState(() {     // 告诉Flutter:数据变了!
  todos.add(item); // 请刷新界面!
});

// 3. Build方法 - 构建界面

Widget build(BuildContext context) {
  return Scaffold(  // 脚手架,页面的骨架
    appBar: AppBar(),  // 顶部栏
    body: Column(),    // 内容区域
  );
}

7.2 学习路线图

# 我的移动应用开发学习进度记录

## 第一周的学习进展

### 第1天:基础运行
成功运行了这个待办事项应用的基本版本。通过Android Studio搭建了开发环境,了解了项目结构,并实现了应用的基本启动功能。

### 第2天:界面优化
- 修改了应用的文字内容,使其更符合个人使用习惯
- 调整了配色方案,将默认蓝色主题改为更柔和的绿色系
- 优化了按钮的圆角半径和阴影效果

### 第3天:功能增强
添加了"紧急程度"字段,包含三个等级:
1. 低优先级(绿色标记)
2. 中优先级(黄色标记) 
3. 高优先级(红色标记)

### 第4天:数据持久化
学习了使用SharedPreferences和SQLite两种方式保存数据:
- 实现了简单的任务列表本地存储
- 测试了应用关闭后数据恢复功能

### 第5天:分类管理
为待办事项添加了分类功能:
- 工作类
- 生活类
- 学习类
- 其他类

## 阶段性成果

### 第1周里程碑
已经能够独立完成以下修改:
- 调整界面布局
- 修改功能逻辑
- 添加简单的新功能

### 第1个月目标
计划实现:
1. 开发一个全新的天气查询应用
2. 包含城市选择功能
3. 实现天气数据API调用
4. 完成基本UI设计

目前正在学习网络请求和JSON数据处理相关知识,为开发完整应用做准备。

🎯 第八章:扩展练习

8.1 小任务挑战

// 任务1:添加时间戳
// 修改TodoItem类,添加DateTime字段
class TodoItem {
  String title;
  bool completed;
  DateTime createdTime;  // 添加这个
  
  TodoItem({
    required this.title,
    this.completed = false,
    required this.createdTime,  // 修改这里
  });
}

// 任务2:添加优先级别
// 1 = 低, 2 = 中, 3 = 高
int priority = 1;

// 任务3:添加搜索功能
// 在输入框下面添加搜索框

8.2 功能升级路线

  1. 基础版(已完成):增删改查
  2. 升级版:添加分类、标签
  3. 高级版:同步到云端、多设备同步
  4. 专业版:数据分析、智能提醒

📚 第九章:学习资源

9.1 必看网站

  1. Flutter中文网:flutter.cn
  2. Dart编程语言:dart.cn
  3. CSDN Flutter社区:搜索"Flutter入门"
  4. B站视频教程:搜索"Flutter 30分钟"

9.2 推荐学习顺序

HTML/CSS基础

JavaScript基础

Flutter基础

第一个应用

学习状态管理

学习网络请求

学习数据库

项目实战

🎉 第十章:写在最后

10.1 我学到什么

  1. 编程不难:就是告诉电脑做什么
  2. Flutter很友好:写UI像搭积木
  3. 鸿蒙很强大:一次开发,多端运行
  4. 最重要的是开始:写第一行代码

10.2 给新手的建议

// 我的学习心得:
1. ✅ 从简单开始 - 别一开始就做大项目
2. ✅ 多动手敲 -10遍不如写13. ✅ 别怕报错 - 每个错误都是学习机会
4. ✅ 加入社区 - 很多人愿意帮忙
5. ✅ 坚持每天 - 哪怕只写30分钟

欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

Logo

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

更多推荐