Flutter 终于有自己的 React Flow 了,vyuh_node_flow 上手实录

话说去年搞鸿蒙开发者激励时,我曾想到搞一个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 可以直接上手体验。

相关推荐
狂师1 小时前
爆火!新一代e2e AI测试框架,单日狂揽1500 star
前端·人工智能·测试
恋猫de小郭1 小时前
Flitz ,一个把 Flutter 玩成热插拔 Preview 的有趣项目,不错的思路
android·前端·flutter
闭包不眠1 小时前
Word转HTML后体积不对,裁掉的截图原图还在
前端·图像处理·人工智能·计算机视觉·html·word
言乐61 小时前
PythonLOLM自动生成复盘报告模型
开发语言·前端·数据库·人工智能·python
tryCbest1 小时前
第二篇:CSS3 全部知识点全解 + 项目样式实现
前端·css·css3
一木 之林1 小时前
Agent智能体学习总结:从一次调用到模型自主规划、工具调用与 ReAct 循环的项目实战-6/6
前端·人工智能·学习·react.js
程序员大阳2 小时前
副队长CSS教程(36)–移动布局与响应式
前端·css·响应式·媒体查询·移动布局
程序员Sunday2 小时前
React 的 useEffect 怎么工作?依赖数组、清理函数和重复执行如何理解?
前端·javascript
lank_M2 小时前
Word裁剪图片转HTML走样,该在渲染层修还是入口修
前端·图像处理·人工智能·计算机视觉·html·word