Flutter 鸿蒙开发实践:利用三方库集成实现跨端动态交互式任务看板

利用三方库集成实现跨端动态交互式任务看板

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

Flutter 鸿蒙开发实践:利用三方库集成实现跨端动态交互式任务看板

1. 前言

鸿蒙(HarmonyOS)应用生态中,高交互性的生产力工具(如项目管理、协作软件)是重要的应用类别。本文将教你如何利用 Flutter 结合三方库 reorderables,从零构建一个支持拖拽排序的任务看板(Kanban)。该案例不依赖任何硬件,非常适合在虚拟机上进行深度开发与调试。

2. 核心关键词

  • Flutter: 跨端高性能 UI 框架。
  • 三方库: reorderables (列表拖拽排序增强库)。
  • 鸿蒙: HarmonyOS Next 运行环境(虚拟机 100% 兼容)。
  • 任务看板: 支持拖拽、跨列移动、状态流转的交互式任务管理界面。

3. 项目案例:Harmony Kanban

模拟一个任务进度管理界面,包含“待处理(To Do)”、“进行中(Doing)”和“已完成(Done)”三个列,用户可以通过点击或拖拽来调整任务顺序、修改任务状态,实现轻量化项目管理。

3.1 核心功能

  • 三列任务状态分组展示
  • 单列内拖拽排序
  • 跨列拖拽修改任务状态
  • 任务卡片点击展开详情
  • 鸿蒙虚拟机全流程兼容运行

4. 第一步:引入三方库

pubspec.yaml 中引入拖拽排序库,它比 Flutter 原生的 ReorderableListView 功能更强大,动画更平滑。

dependencies:
  flutter:
    sdk: flutter
  # 三方库:提供高性能、可定制的列表拖拽排序功能
  reorderables: ^0.6.0
  # 状态管理
  provider: ^6.1.1

执行安装:

flutter pub get

5. 第二步:任务数据模型

创建 lib/models/task\_model\.dart

class Task {
  final String id;
  final String title;
  final String content;
  final String status; // todo / doing / done

  Task({
    required this.id,
    required this.title,
    required this.content,
    required this.status,
  });

  Task copyWith({String? status}) {
    return Task(
      id: id,
      title: title,
      content: content,
      status: status ?? this.status,
    );
  }
}

6. 第三步:状态管理

创建 lib/providers/task\_provider\.dart

import 'package:flutter/foundation.dart';
import '../models/task_model.dart';

class TaskProvider extends ChangeNotifier {
  List<Task> todoList = [];
  List<Task> doingList = [];
  List<Task> doneList = [];

  TaskProvider() {
    _initMockData();
  }

  void _initMockData() {
    todoList = [
      Task(id: "1", title: "设计页面原型", content: "完成鸿蒙看板UI设计", status: "todo"),
      Task(id: "2", title: "集成reorderables", content: "配置依赖并实现基础拖拽", status: "todo"),
    ];
    doingList = [
      Task(id: "3", title: "开发跨列移动", content: "实现任务在三列之间拖动", status: "doing"),
    ];
    doneList = [
      Task(id: "4", title: "环境搭建", content: "Flutter+鸿蒙开发环境配置完成", status: "done"),
    ];
    notifyListeners();
  }

  // 单列内排序
  void reorderTodo(int oldIdx, int newIdx) {
    final item = todoList.removeAt(oldIdx);
    todoList.insert(newIdx, item);
    notifyListeners();
  }

  void reorderDoing(int oldIdx, int newIdx) {
    final item = doingList.removeAt(oldIdx);
    doingList.insert(newIdx, item);
    notifyListeners();
  }

  void reorderDone(int oldIdx, int newIdx) {
    final item = doneList.removeAt(oldIdx);
    doneList.insert(newIdx, item);
    notifyListeners();
  }

  // 跨列移动任务
  void moveTask(Task task, String from, String to) {
    if (from == "todo") todoList.remove(task);
    if (from == "doing") doingList.remove(task);
    if (from == "done") doneList.remove(task);

    final newTask = task.copyWith(status: to);
    if (to == "todo") todoList.add(newTask);
    if (to == "doing") doingList.add(newTask);
    if (to == "done") doneList.add(newTask);

    notifyListeners();
  }
}

7. 第四步:任务卡片组件

创建 lib/widgets/task\_card\.dart

import 'package:flutter/material.dart';
import '../models/task_model.dart';

class TaskCard extends StatelessWidget {
  final Task task;
  final Function(LongPressStartDetails)? onLongPress;

  const TaskCard({super.key, required this.task, this.onLongPress});

  
  Widget build(BuildContext context) {
    return Container(
      key: ValueKey(task.id),
      margin: const EdgeInsets.symmetric(vertical: 4),
      padding: const EdgeInsets.all(12),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(8),
        boxShadow: [
          BoxShadow(color: Colors.black12, blurRadius: 2, offset: Offset(1, 1))
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(task.title, style: TextStyle(fontWeight: FontWeight.bold)),
          SizedBox(height: 4),
          Text(task.content, style: TextStyle(color: Colors.grey[700], fontSize: 12)),
        ],
      ),
    );
  }
}

8. 第五步:看板主界面

创建 lib/pages/kanban\_page\.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:reorderables/reorderables.dart';
import '../providers/task_provider.dart';
import '../widgets/task_card.dart';
import '../models/task_model.dart';

class KanbanPage extends StatelessWidget {
  const KanbanPage({super.key});

  
  Widget build(BuildContext context) {
    final taskProvider = Provider.of<TaskProvider>(context);

    Widget buildColumn(String title, List<Task> tasks, String status, Function(int, int) onReorder) {
      return Expanded(
        child: Container(
          margin: const EdgeInsets.all(6),
          padding: const EdgeInsets.all(8),
          color: Colors.grey[100],
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(title, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
              SizedBox(height: 8),
              Expanded(
                child: ReorderableColumn(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  onReorder: onReorder,
                  children: tasks.map((task) {
                    return LongPressDraggable<Task>(
                      key: ValueKey(task.id),
                      data: task,
                      feedback: Material(
                        elevation: 4,
                        child: SizedBox(width: 200, child: TaskCard(task: task)),
                      ),
                      childWhenDragging: Opacity(opacity: 0.5, child: TaskCard(task: task)),
                      child: TaskCard(task: task),
                    );
                  }).toList(),
                ),
              ),
            ],
          ),
        ),
      );
    }

    return Scaffold(
      appBar: AppBar(title: const Text("Harmony Kanban 任务看板")),
      body: Row(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          buildColumn("待处理 ToDo", taskProvider.todoList, "todo", (o, n) => taskProvider.reorderTodo(o, n)),
          buildColumn("进行中 Doing", taskProvider.doingList, "doing", (o, n) => taskProvider.reorderDoing(o, n)),
          buildColumn("已完成 Done", taskProvider.doneList, "done", (o, n) => taskProvider.reorderDone(o, n)),
        ],
      ),
    );
  }
}

9. 第六步:主入口配置

lib/main\.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'providers/task_provider.dart';
import 'pages/kanban_page.dart';

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => TaskProvider(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Harmony Kanban',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const KanbanPage(),
      debugShowCheckedModeBanner: false,
    );
  }
}

10. 鸿蒙虚拟机运行

  1. 启动 DevEco Studio 中的 HarmonyOS Next 虚拟机

  2. 执行:

flutter run -d harmony
  1. 即可在鸿蒙环境中运行拖拽式任务看板

11. 功能说明

  • 单列拖拽:长按卡片可上下排序

  • 跨列移动:长按拖动到另一列即可修改任务状态

  • 状态实时同步:Provider 管理全局数据,UI 自动刷新

  • 鸿蒙兼容:无原生依赖,虚拟机 100% 正常运行

12. 扩展方向

  • 添加任务新增 / 编辑 / 删除

  • 接入鸿蒙本地数据库持久化

  • 支持深色模式、平板横屏布局

  • 对接鸿蒙服务卡片、通知提醒

  • 支持多人协作、云端同步

运行截图:
在这里插入图片描述

Logo

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

更多推荐