Flutter甘特图展示插件gantt_view的使用

发布于 1周前 作者 caililin 来自 Flutter

Flutter甘特图展示插件gantt_view的使用

特性

  • 固定的任务名称列
  • 固定的日期图例行
  • 可自定义的任务栏颜色
  • 可自定义的任务栏高度
  • 可自定义的任务栏间距
  • 可自定义的任务栏圆角半径
  • 能够在日视图和周视图之间切换
  • 显示周末的不同颜色
  • 可自定义周末颜色
  • 自定义高亮日期
  • 可自定义高亮日期颜色
  • 任务栏悬停或点击时显示提示信息
  • 可自定义提示样式

使用

Gantt Example

所有需要做的就是传入一个带有List<GridRow>GanttChart<T>小部件。List<GridRow>是一个包含<ActivityGridRow>TaskGridRow的对象列表,构造方法的例子可以在example\lib\main.dart文件中找到。

该插件还提供了基本的主题选项,用于自定义GanttChart的外观,例如改变行的外观以及是否显示头部。

ActivityGridRowTaskGridRowGanttChart中可以显示的两种类型的行。ActivityGridRow是一种显示任务组标题的行,而TaskGridRow是一种显示任务的行。要自定义行的外观,可以向GanttChart小部件提供一个GanttRowStyleGanttRowStyle有两个字段,activityLabelBuildertaskLabelBuilder,分别用于自定义ActivityGridRowTaskGridRow的外观。

其他自定义选项包括更改网格线的颜色、周末列的颜色以及高亮日期的颜色。GanttChart还可以在悬停或点击任务时显示提示信息。

GanttChart<ExampleEventItem>(
    rows: _items.toRows(),
    style: GanttStyle(
        columnWidth: 100,
        barHeight: 16,
        timelineAxisType: TimelineAxisType.daily,
        tooltipType: TooltipType.hover,
        taskBarColor: Colors.blue.shade400,
        activityLabelColor: Colors.blue.shade500,
        taskLabelColor: Colors.blue.shade900,
        taskLabelBuilder: (task) => TaskLabel(task),
        gridColor: Colors.grey.shade300,
        taskBarRadius: 8,
        activityLabelBuilder: (activity) => ActivityLabel(activity),
        axisDividerColor: Colors.grey.shade500,
        tooltipColor: Colors.redAccent,
        tooltipPadding:
            const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
        weekendColor: Colors.grey.shade200,
        snapToDay: false,
    ),
    dateLines: [
        GanttDateLine(
            date: DateTime.timestamp(), width: 2, color: Colors.orangeAccent),
        GanttDateLine(
            date: DateTime.timestamp().add(const Duration(days: 2)),
        ),
    ],
)

样式

属性 类型
taskBarColor Color
taskBarRadius double
taskLabelColor Color
activityLabelColor Color
chartTitleBuilder Widget Function()?
taskLabelBuilder Widget Function(TaskGridRow)
activityLabelBuilder Widget Function(ActivityGridRow activity)?
yearLabelBuilder Widget Function(int year)
monthLabelBuilder Widget Function(Month month)
dayLabelBuilder Widget Function(int day)
gridColor Color?
weekendColor Color?
holidayColor Color
axisDividerColor Color?
tooltipColor Color
tooltipStyle TextStyle
tooltipPadding EdgeInsets
tooltipRadius double
barHeight double
columnWidth double
tooltipWidth double
labelColumnWidth double
snapToDay bool
showYear bool
showMonth bool
showDay bool
timelineAxisType TimelineAxisType
tooltipType TooltipType

其他信息

这是一个正在进行中的项目,尚未准备好用于生产环境。API可能会发生变化。欢迎提供反馈,也欢迎提交拉取请求。

待办事项

  • ❌ 添加缩放功能
  • ✅ 添加自定义单个任务栏颜色的功能
  • ❌ 添加为整个图表定义自定义开始和结束时间的功能
  • ❌ 测试
  • ❌ 添加定义图例高度、标签列宽度的功能,覆盖自动计算的值
  • ❌ 添加隐藏图例的功能
  • ❌ 添加隐藏标题/标签的功能
  • ❌ 添加设置一周第一天的功能
  • ❌ 添加将高亮日和周末日设置为纯色的功能,以便任务栏不可见
  • ❌ 添加滚动条
  • ✅ 添加日期线以允许用户显示重要日期

当前已知问题

  • ❌ 有时在实例化时,图表的平移偏移没有正确更新,导致平移速度比预期慢。
  • ❌ 大量数据项列表可能导致图表渲染缓慢,原因如下:
    • 将大量数据排序为活动和任务;
    • 基于最长标签计算标签列的宽度;
    • 目前通过为每个标签运行一个实用函数来获取宽度,然后取所有标签的最大宽度,这效率不高。
  • ✅ 当调整大小时,图表可能会尝试渲染超出其边界的区域,而不是更新平移偏移到新边界。
  • ❌ 非UTC时间的日期在跨越夏令时时区变更时可能会出现问题,因为图表不考虑夏令时。
  • ❌ 在网页端,有时使用水平鼠标滚轮无法进行水平滚动。

示例代码

import 'package:example/data.dart';
import 'package:flutter/material.dart';
import 'package:gantt_view/gantt_view.dart';

void main() {
  runApp(const MyApp());
}

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

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        useMaterial3: true,
      ),
      home: const MyHomePage(),
      debugShowCheckedModeBanner: false,
    );
  }
}

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

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final List<ExampleEventItem> _items = Data.dummyData;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      body: GanttChart<ExampleEventItem>(
        rows: _items.toRows(),
        showCurrentDate: true,
        style: GanttStyle(
          columnWidth: 50,
          barHeight: 16,
          timelineAxisType: TimelineAxisType.daily,
          tooltipType: TooltipType.hover,
          taskBarColor: Colors.blue.shade400,
          activityLabelColor: Colors.blue.shade500,
          taskLabelColor: Colors.blue.shade900,
          taskLabelBuilder: (task) => Container(
            padding: const EdgeInsets.all(4),
            child: Text(
              task.data.title,
              style: const TextStyle(
                fontWeight: FontWeight.bold,
                color: Colors.white,
              ),
            ),
          ),
          gridColor: Colors.grey.shade300,
          taskBarRadius: 8,
          activityLabelBuilder: (activity) => Container(
            padding: const EdgeInsets.all(4),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  activity.label!,
                  style: const TextStyle(
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                ),
                const Text(
                  'A subtitle',
                  style: TextStyle(
                    fontStyle: FontStyle.italic,
                    color: Colors.white,
                  ),
                ),
              ],
            ),
          ),
          axisDividerColor: Colors.grey.shade500,
          tooltipColor: Colors.redAccent,
          tooltipPadding:
              const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
          weekendColor: Colors.grey.shade200,
          dateLineColor: Colors.red,
          snapToDay: false,
        ),
        dateLines: [
          GanttDateLine(
              date: DateTime.timestamp(), width: 2, color: Colors.orangeAccent),
          GanttDateLine(
            date: DateTime.timestamp().add(const Duration(days: 2)),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        backgroundColor: Colors.redAccent,
        onPressed: () => setState(() => _items.addAll(Data.dummyData)),
        child: const Icon(Icons.restore, color: Colors.white),
      ),
    );
  }
}

extension on DateTime {
  String get formattedDate => '$day/$month/$year';
}

extension on List<ExampleEventItem> {
  List<GridRow> toRows() {
    List<GridRow> rows = [];
    Map<String, List<TaskGridRow<ExampleEventItem>>> labelTasks = {};

    sort((a, b) => a.start.compareTo(b.start));

    for (var item in this) {
      final label = item.group;
      (labelTasks[label] ??= []).add(TaskGridRow<ExampleEventItem>(
        data: item,
        startDate: item.start,
        endDate: item.end,
        tooltip: '${item.title}\n${item.start.formattedDate} - ${item.end.formattedDate}',
      ));
    }

    for (var label in labelTasks.keys) {
      rows.add(ActivityGridRow(label));
      rows.addAll(labelTasks[label]!);
    }

    return rows;
  }
}

更多关于Flutter甘特图展示插件gantt_view的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter甘特图展示插件gantt_view的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用gantt_view插件来展示甘特图的代码案例。gantt_view是一个用于在Flutter应用中展示甘特图的插件。以下步骤将展示如何集成和使用这个插件。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加gantt_view依赖:

dependencies:
  flutter:
    sdk: flutter
  gantt_view: ^最新版本号  # 请替换为实际的最新版本号

然后运行flutter pub get来安装依赖。

2. 导入包

在你的Dart文件中导入gantt_view包:

import 'package:gantt_view/gantt_view.dart';

3. 准备数据

甘特图的数据通常包括任务名称、开始时间、结束时间等。你需要准备一个包含这些信息的列表。

class Task {
  String name;
  DateTime startDate;
  DateTime endDate;

  Task({required this.name, required this.startDate, required this.endDate});
}

List<Task> tasks = [
  Task(name: 'Task 1', startDate: DateTime(2023, 10, 1), endDate: DateTime(2023, 10, 5)),
  Task(name: 'Task 2', startDate: DateTime(2023, 10, 3), endDate: DateTime(2023, 10, 8)),
  Task(name: 'Task 3', startDate: DateTime(2023, 10, 7), endDate: DateTime(2023, 10, 10)),
];

4. 创建甘特图

在你的Flutter组件中使用GanttView来展示甘特图。

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Gantt View Example'),
        ),
        body: GanttViewExample(),
      ),
    );
  }
}

class GanttViewExample extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GanttView(
      tasks: _convertToGanttTasks(tasks),
      timeScale: const TimeScale(
        start: DateTime(2023, 10, 1),
        end: DateTime(2023, 10, 15),
        interval: TimeInterval.day,
      ),
      onTaskSelected: (task) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Task selected: ${task.name}')),
        );
      },
    );
  }

  List<GanttTask> _convertToGanttTasks(List<Task> tasks) {
    return tasks.map((task) => GanttTask(
          name: task.name,
          startDate: task.startDate,
          endDate: task.endDate,
        )).toList();
  }
}

5. 运行应用

现在,你可以运行你的Flutter应用,应该能够看到甘特图展示了你的任务数据。

注意事项

  • GanttViewtasks属性需要一个List<GanttTask>类型的列表,其中GanttTaskgantt_view包中定义的类。你需要将你的任务数据转换为GanttTask对象。
  • TimeScale定义了甘特图的时间轴范围和时间间隔。你可以根据需要调整这些参数。
  • onTaskSelected是一个可选的回调,当用户点击某个任务时会触发。

通过上述步骤,你应该能够在Flutter应用中成功集成并使用gantt_view插件来展示甘特图。

回到顶部