🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

Flutter 也有類 React Flow 的節點流程編輯器,快來了解下剛剛開源的 vyuh_node_flow

vyuh_node_flow 是一個剛剛開源的 Flutter Flow 節點編輯器,這是一個基於 MIT 许可的全平台節點/圖形編輯器工具,它提供了類似 React Flow 的一系列功能支持:

image

基於 vyuh_node_flow ,你可以實現:

  • 可視化編程介面: 創建像 Scratch 或 Unreal Engine Blueprints 那樣的圖形化編程環境
    image

  • 工作流編輯器: 設計和編輯業務流程、數據處理流程或自動化任務
    image

  • 互動式圖表: 構建組織結構圖、思維導圖、狀態機等

  • 數據管道: 可視化地定義和管理數據流和處理步驟

另外,作為一個純粹的 Flutter SDK,它支持所有平台,提供大量開箱即用功能,例如:

  • 支持為 100+ 個節點和無限畫布提供高性能渲染
  • 具有泛型的完全類型安全節點
  • 支持響應式主題化,可以更改節點主題、連接主題、樣式等
  • 背景支持配置網格、點陣、層級網格或純色
  • 支持平移和自定義定位的大型圖表迷你地圖 (Minimap),方便在複雜的流程圖中導航
    image
  • 支持標記、便簽、群組等註解功能,可以在畫布上添加標籤、註解(如便簽 StickyAnnotation、標記 MarkerAnnotation)和自定義覆蓋物,註解可以跟隨節點移動
  • 可以創建自定義節點和節點容器
    image
  • 支持自定義繪製連接線,內置對貝塞爾曲線、直線、階梯和平滑階梯繪圖器的支持
  • 支持多種端口形狀(半膠囊、圓形、方形、菱形、三角形)、位置(上、下、左、右)和偏移量,並支持連接驗證
  • 支持將整個圖(包括節點、連接、註解、視口狀態)導出為 JSON 或從 JSON 加載
  • 支持豐富的鍵盤快捷鍵操作(如全選、複製、粘貼、刪除、縮放、對齊等)
  • 支持節點對齊
  • 只讀支持,提供 NodeFlowViewer 組件,用於僅顯示流程圖,禁止編輯
  • ·····

image

通過源碼可以看到,這是一個相當完整的 Flow 編輯器,並且它的整體設計思路也很有意思,其中包括:

  • 狀態管理: 它內置直接使用 MobX 自動處理狀態更新和 UI 響應,如節點位置、選擇狀態的變化會自動觸發相關 UI 的重繪

  • 分層渲染: 通過 CustomPaintStack 實現,編輯器將不同的元素(網格、背景註解、連接線、連接標籤、節點、前景註解、交互元素)渲染在不同的層 (Layer) 中,例如連接標籤在單獨的層中渲染,避免連接線重繪時標籤也重繪

  • 可定制的節點渲染: 通過 nodeBuildernodeContainerBuilder 允許用戶完全自定義節點的內部內容和外部容器樣式

  • 連接線樣式: ConnectionStyles 提供了多種內置樣式,並且路徑計算邏輯 (ConnectionPathCalculator, SmoothstepPathCalculator 等) 也被抽象出來,便於擴展自定義樣式

  • 連接驗證: 提供了 onBeforeStartConnectiononBeforeCompleteConnection 回調,允許開發者在連接開始和完成前進行自定義邏輯驗證,例如檢查端口類型兼容性、防止循環連接等

  • 註解系統: 支持多種類型的註解,並且 GroupAnnotation 可以自動包圍其依賴的節點並跟隨移動,StickyAnnotationMarkerAnnotation 也可以通過 dependencies 跟隨節點

  • 快捷鍵與動作系統: 內置了豐富的快捷鍵操作 (NodeFlowShortcutManager, NodeFlowAction),並且易於擴展和自定義,並且提供了 ShortcutsViewerDialog 來顯示所有可用的快捷鍵。

  • 性能相關優化設計:

    • 使用 Observer 包裹需要響應式更新的 Widget 部分,实现局部刷新
    • 使用 RepaintBoundary 隔離複雜的繪製層(如連接線層、節點層),避免不必要的重繪
    • 連接線路徑和命中測試路徑的緩存 (ConnectionPathCache)
    • 空間索引 (SpatialIndex) 用於優化大量節點的查詢和命中測試
  • 序列化與反序列化: 提供了方便的方法 (toJsonString, fromJsonString, fromUrl, fromAsset) 來保存和加載圖的狀態

也就是,vyuh_node_flow 在項目裡大量使用了 MobX 用於響應式狀態管理,代碼中廣泛使用 Observable, Computed, action, reaction, runInAction 以及 Observer 來實現 UI 和狀態響應,同時放大縮小和平移主要依賴 Flutter 內置的 InteractiveViewer 實現。

相對應的,vyuh_node_flow 也有比較複雜的 API 結果,其中核心 API 有:

  • NodeFlowController<T>: 核心狀態管理器,負責管理節點、連接、註解、視口、配置、主題和交互狀態,它通過使用 MobX 的 Observable 來實現響應式更新
  • NodeFlowEditor<T>: 主要的編輯器控件,接收 NodeFlowController,負責渲染畫布、節點、連接、註解,並處理用戶交互(拖拽、連接、選擇、平移、縮放)
  • NodeFlowViewer<T>: 只讀模式的 Widget,基於 NodeFlowEditor 但禁用了編輯功能
  • Node<T>: 代表畫布上的一個節點,包含 ID、類型、位置、尺寸、數據 (T) 以及輸入/輸出端口列表,而位置 (position) 和視覺位置 (visualPosition) 是分離的 Observable,後者用於應用網格吸附後的渲染
  • Port: 定義節點的連接點,包含 ID、名稱、位置 (PortPosition)、形狀 (PortShape)、類型 (PortType,如 source/target/both)、是否允許多重連接等屬性
  • Connection: 代表節點間的一條連接線,包含 ID、源/目標節點 ID、源/目標端口 ID,以及可選的標籤 (label, startLabel, endLabel) 和樣式 (style)
  • Annotation: 註解的基類,子類包括 StickyAnnotation (便簽)、GroupAnnotation (節點分組)、MarkerAnnotation (標記),註解可以有自己的位置、尺寸、樣式,並且可以通過 dependencies 相關聯節點
  • NodeFlowTheme: 定義編輯器所有視覺元素的樣式,包括節點、連接線、端口、背景、網格、選擇框等的顏色、大小、形狀、字體等,包含 NodeTheme, ConnectionTheme, PortTheme, LabelTheme
  • NodeFlowConfig: 控制編輯器的行為,如是否啟用網格吸附、小地圖、縮放範圍、自動平移等
  • NodeGraph<T>: 用於序列化和反序列化的數據結構,包含節點、連接、註解和視口狀態
  • ·····

運行庫提供的 MVP 示例,可以看到使用起來也不是很複雜,通過向 controller 添加兩個 Node ,然後添加到 NodeFlowEditor ,並通過 _buildNode 渲染需要的節點,就可以得到一個可交互連接的 Flow 顯示:

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

class SimpleFlowEditor extends StatefulWidget {
  @override
  State<SimpleFlowEditor> createState() => _SimpleFlowEditorState();
}

class _SimpleFlowEditorState extends State<SimpleFlowEditor> {
  late final NodeFlowController<String> controller;

  @override
  void initState() {
    super.initState();

    // 1. Create the controller
    controller = NodeFlowController<String>();

    // 2. Add some nodes
    controller.addNode(Node<String>(
      id: 'node-1',
      type: 'input',
      position: const Offset(100, 100),
      data: 'Input Node',
      outputPorts: const [Port(id: 'out', name: 'Output')],
    ));

    controller.addNode(Node<String>(
      id: 'node-2',
      type: 'output',
      position: const Offset(400, 100),
      data: 'Output Node',
      inputPorts: const [Port(id: 'in', name: 'Input')],
    ));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: NodeFlowEditor<String>(
        controller: controller,
        theme: NodeFlowTheme.light,
        nodeBuilder: (context, node) => _buildNode(node),
      ),
    );
  }

  Widget _buildNode(Node<String> node) {
    return Container(
      padding: const EdgeInsets.all(16),
      child: Text(node.data),
    );
  }
}

image

根據前面的 API ,我們可以簡單拼接出 vyuh_node_flow 的實現原理:

  • 核心: NodeFlowController 作為中心樞紐,存儲所有狀態 (節點、連接、視口等) 的 Observable 實例
  • 渲染: NodeFlowEditor
    • 使用 Stack 組織不同的渲染層 (GridLayer, ConnectionsLayer, NodesLayer, AnnotationLayer 等)
    • NodesLayerAnnotationLayer 使用 PositionedObserver 來渲染每個節點/註解,只在位置等 Observable 變化時重繪
    • ConnectionsLayerGridLayer 使用 CustomPaintObserver 來繪製連接線和網格,響應節點位置和視口的變化
  • 交互: NodeFlowEditor 使用 Listener, GestureDetector, MouseRegion 監聽原始指針事件
    • 事件發生時,它會進行命中測試 (_performHitTest) 以確定交互物件(畫布、節點、端口、連接、註解),然後調用 NodeFlowController 中對應的內部方法 (_startNodeDrag, _moveNodeDrag, _startConnection, _completeConnection, _updateSelectionDrag 等)來更新 MobX 狀態
    • 這些狀態更新會自動觸發相關 Observer Widget 的重繪
  • 連接線繪製: ConnectionPainter 負責繪製連接線
    • 它使用 ConnectionPathCache 來緩存計算出的 Path 對象
    • 當需要繪製或進行命中測試時,它會先檢查緩存
    • 如果緩存無效(例如節點移動了),則重新計算路徑(委託給具體的 ConnectionStyle 實現)並更新緩存
  • 狀態更新: 所有狀態變更都通過 NodeFlowController 的方法進行,內部使用 runInAction 來確保 MobX 的原子更新

image

從代碼結構和使用的技術來看,vyuh_node_flow 也採用了多種提升性能的策略:

  • MobX:僅在狀態變化時更新必要的 UI 部分
  • 分層渲染 (Layered Rendering):使用 Stack 將網格、連接線、節點、註解等分層繪製,並通過 RepaintBoundary 隔離複雜的繪製層,減少不必要的重繪範圍
  • 路徑緩存 (ConnectionPathCache):緩存連接線的計算路徑 (Path) 和用於命中測試的路徑,避免在每次重繪或交互時重複計算
  • 空間索引 (SpatialIndex): (lib/shared/spatial_index.dart, lib/shared/node_spatial_adapter.dart) 使用基於網格的空間索引,來快速查詢可見區域內的節點或與特定區域重疊的節點,這對於節點數量較多時的性能至關重要,避免了遍歷所有節點進行可見性判斷或命中測試

總的來說,vyuh_node_flow 是一個功能豐富、設計良好且注重性能的 Flutter 節點編輯器庫,特別適合需要高度自定義和交互性的可視化流程編輯場景,儘管目前還缺失一些複雜的圖形自動佈局算法,但是可用性已經相當成熟,至少對於 Flutter 開發者來說,這是一個不錯的支持。

根據作者的說法,這也是一個致敬 React Flow 的項目
image

參考鏈接

github.com/vyuh-tech/v…


原文出處:https://juejin.cn/post/7566426081579155462


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝26   💬5   ❤️7
800
🥈
我愛JS
📝2   💬7   ❤️3
118
🥉
酷豪
1
#5
1
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付