
话说去年搞鸿蒙开发者激励时,我曾想到搞一个Xmind之类的APP。说实话,与其相信我自己可以写一个这么复杂的系统,还不如相信自己是秦始皇。这种节点图、连线、缩放平移的东西,交互细节特别多,自己从零开始写,文件夹刚建就得烂尾。由于当时我的那几个app全是flutter做的。所以我就尝试找一个可视化的流程编辑器库,让用户能自己拖拽节点、连线、拼出一个工作流。没想到还真让找到了:vyuh_node_flow。
01 它到底是什么
简单地说:Flutter 里的 React Flow。
前端同学应该都知道 React Flow,React 生态里做节点图编辑器的事实标准,GitHub 上两万多 star。而 vyuh_node_flow 的作者也很坦诚,在 README 里直接写明这个项目就是 inspired by React Flow。
但它是纯 Dart 写的,原生 Flutter Widget,不依赖任何 JS 引擎或 WebView。这意味着它跑在 iOS、Android、桌面、Web 上都是一套代码,没有跨端的心智负担。
那它能拿来干什么?我总结了四类典型场景:
- 可视化编程界面------像 Scratch 或者 Unreal Engine 蓝图那种,拖节点、连线、拼逻辑。
- 工作流编辑器------业务流程、数据处理、自动化任务的可视化编排。
- 交互式图表------组织架构图、思维导图、状态机。
- 数据管道------把数据流向和处理步骤画出来,看得见摸得着。
说白了,凡是「节点 + 连线」能表达的图,它都能接。
官方 Demo 里的实际交互效果
02 上手有多快
我试了下,从零跑通一个能拖拽、能连线的流程图,大概三十行代码。
核心就三步:建一个 Controller、塞几个 Node 进去、丢给 NodeFlowEditor 渲染。
dart
import 'package:flutter/material.dart';
import 'package:vyuh_node_flow/vyuh_node_flow.dart';
class FlowEditor extends StatefulWidget {
@override
State<FlowEditor> createState() => _FlowEditorState();
}
class _FlowEditorState extends State<FlowEditor> {
// 1. 建一个 Controller,泛型是你的节点数据类型
late final controller = NodeFlowController<String, dynamic>(
nodes: [
Node<String>(
id: 'node-1',
type: 'input',
position: const Offset(100, 100),
data: '开始',
outputPorts: const [
Port(id: 'out', name: 'Output', offset: Offset(2, 40)),
],
),
Node<String>(
id: 'node-2',
type: 'output',
position: const Offset(400, 100),
data: '结束',
inputPorts: const [
Port(id: 'in', name: 'Input', offset: Offset(-2, 40)),
],
),
],
// 2. 把两个节点连起来
connections: [
Connection(
id: 'conn-1',
sourceNodeId: 'node-1',
sourcePortId: 'out',
targetNodeId: 'node-2',
targetPortId: 'in',
),
],
);
@override
Widget build(BuildContext context) {
// 3. 丢给编辑器,配一个 nodeBuilder 决定节点长啥样
return NodeFlowEditor<String, dynamic>(
controller: controller,
theme: NodeFlowTheme.light,
nodeBuilder: (context, node) => Padding(
padding: const EdgeInsets.all(16),
child: Text(node.data,
style: const TextStyle(fontWeight: FontWeight.bold)),
),
);
}
}
跑起来就是上面那张 GIF 的样子:两个节点、一条连线,能拖、能选、能缩放。
这里有个小细节我觉得挺关键------它用了泛型。NodeFlowController<String, dynamic> 里的 String 就是你的节点数据类型,nodeBuilder 回调里拿到的 node.data 就是强类型的 String,不用 cast、不用 as。作者也建议用 sealed class 做节点数据层级,配合 switch 表达式做模式匹配,类型安全能拉满。
这对 Flutter 开发者来说很对味,比那些靠 Map<String, dynamic> 传数据的库舒服太多了。
03 设计上有点东西
光看 API 用法不够过瘾,我去翻了翻源码,发现这个库的内部设计其实有点东西,不是那种「能跑就行」的玩具项目。
状态管理用了 MobX
项目里大量用了 Observable、Computed、action、Observer 这套 MobX 模式。节点位置、选中状态这些是 Observable,一变,对应的 Observer Widget 自动重绘,不用你手动 setState。好处是局部刷新很精准,不会因为一个节点动了,整张图重绘一遍。
分层渲染
编辑器内部用 Stack 把不同元素分到不同层:网格层、背景注解层、连接线层、连接标签层、节点层、前景注解层、交互层。连接标签单独一层是有讲究的------连接线重绘时,标签不用跟着重绘。再配合 RepaintBoundary 隔离每层,把重绘范围压到最小。
性能上做了几层缓存
连接线的 Path 算出来之后会缓存(ConnectionPathCache),命中测试也复用这条缓存,节点不动就不重算。还有一个基于网格的空间索引(SpatialIndex),查「这块区域有哪些节点」不用遍历全量,几百个节点时命中测试仍然快。官方说 100+ 节点能稳 60fps,我手头没铺到那个量级,但从实现策略看,不是空口说白话。
平移和缩放主要靠 Flutter 自带的 InteractiveViewer,没自己重新发明轮子,这点我也挺认同的------能用框架能力就用,把精力留给真正难的连接和命中逻辑。
04 几个我觉得亮眼的细节
功能清单谁都能抄,真正区分一个库好坏的是细节。说几个我比较喜欢的。
连接线能做动效
不只是画一条线那么简单。内置了粒子流(Particles)、流动虚线(FlowingDash)、脉冲(Pulse)、渐变(Gradient)、彩虹(Rainbow)几种特效。做数据管道可视化的时候,在线上加个流动虚线,数据「在流」的感觉一下就出来了,比静态箭头生动太多。
主题系统粒度很细
NodeFlowTheme 拆成了 NodeTheme、ConnectionTheme、PortTheme、GridTheme 几个子主题,每个都能 copyWith。深色浅色开箱即用,但要改端口形状、连接线颜色、网格样式,都有一层一层可调。做 toB 产品的人应该会喜欢这种可控度。
dart
final customTheme = NodeFlowTheme.dark.copyWith(
connectionTheme: ConnectionTheme.dark.copyWith(
style: ConnectionStyles.bezier,
color: Colors.purple.shade300,
animationEffect: ConnectionEffects.particles,
),
gridTheme: GridTheme.dark.copyWith(
style: GridStyles.dots,
color: Colors.white24,
),
nodeTheme: NodeTheme.dark.copyWith(
borderRadius: BorderRadius.circular(12),
selectedBorderColor: Colors.purple,
),
);
注解系统能跟着节点走
画布上能贴便签(StickyAnnotation)、打标记(MarkerAnnotation)、框分组(GroupAnnotation)。分组框会自动包围它依赖的节点,节点一动,框跟着伸缩。这在复杂流程图里特别有用------几百个节点没有分组注释,根本没法看。
整图能序列化成 JSON
节点、连接、注解、视口状态,全套 toJson / fromJson。用户拼好的流程图存到后端,下次打开原样恢复,不用自己写序列化。做 toB 工作流产品,这个能力是刚需。
还有几个锦上添花的:迷你地图(Minimap)做大局导航、20 多个内置快捷键、只读模式 NodeFlowViewer 给纯展示场景用、插件式扩展(StatsExtension、DebugExtension、LodExtension)按需挂载。
05 说说不足
夸了这么多,也得说说它现在还缺什么,免得你上手了才发现坑。
最大的缺口是没有自动布局算法。节点位置得你自己给 Offset,或者用户手动拖。如果你有一堆数据想自动生成一张整齐的流程图,vyuh_node_flow 帮不了你,得自己接 dagre、graphviz 这类布局引擎算坐标,再喂给它的 Controller。
另外它还比较年轻,版本号还在 0.x 阶段,API 可能有变动。做正式产品接入前,建议先把 changelog 扫一遍,心里有数。
但话说回来,在 Flutter 生态里,节点流程编辑器这个品类,目前能打的也就它了。React Flow 在前端能长成两万 star 的基础设施,靠的不是一天写完,是几年迭代。vyuh_node_flow 的底子已经铺得不差,缺的是时间和用户反馈。
06 说点更远的
用完 vyuh_node_flow,我更想说的一件事是------Flutter 生态在可视化编辑这块,正在补课。
前端有 React Flow、有 drawflow、有 G6、有 X6,做节点图、关系图、流程图,工具链已经成熟到「npm install 就能跑」。Flutter 这边过去是真空地带,要做类似的东西,要么套 WebView 引一个 JS 库,要么自己啃 CustomPaint 从头造。前者跨端体验割裂,后者成本高得吓人。
vyuh_node_flow 这种纯 Dart 原生方案出现的意义,不只是多一个轮子。它意味着 Flutter 想做 toB 的可视化编辑器、做低代码平台、做工作流编排工具,终于不用在「体验妥协」和「成本爆炸」之间二选一了。
而且它的设计是贴着 Flutter 原生习惯去的------泛型、Widget builder、Theme copyWith、Observable 局部刷新,全是 Flutter 开发者肌肉记忆里的那一套。没有引入一套新的心智模型,学习曲线很平。
如果你最近正好要在 Flutter 里画流程图、做节点编辑、搭可视化编排工具,不妨先拿它试试,别急着造轮子。
项目地址放在下面了,文档站也有在线 Demo 可以直接上手体验。
- GitHub:github.com/vyuh-tech/vyuh_node_flow
- 文档站:flow.vyuh.tech
- 在线 Demo:flow.demo.vyuh.tech