You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求问:如何用Flutter/Dart实现可自定义的类思维导图链接?

Flutter/Dart 实现自定义思维导图方案

针对你要的自定义节点链接效果,给你几个可行的解决方向:

1. 自定义Canvas绘制(最灵活)

如果第三方包满足不了你的自定义需求,直接用CustomPainter手绘节点和连线是最佳选择,完全能复刻图中的样式:

  • 先通过Path构建自定义连线(比如带水平拐点、箭头的线条),用canvas.drawPath绘制
  • 再绘制节点(用RRect做圆角矩形,搭配文字)
  • 配合GestureDetector实现节点拖拽、点击等交互

核心代码片段:

class MindMapPainter extends CustomPainter {
  final List<Node> nodes;
  final List<Link> links;

  MindMapPainter({required this.nodes, required this.links});

  @override
  void paint(Canvas canvas, Size size) {
    // 先画连线(避免被节点遮挡)
    final linkPaint = Paint()
      ..color = Colors.grey.shade400
      ..strokeWidth = 2
      ..style = PaintingStyle.stroke;
    for (var link in links) {
      final startCenter = Offset(
        link.startNode.position.dx + 50,
        link.startNode.position.dy + 30,
      );
      final endCenter = Offset(
        link.endNode.position.dx + 50,
        link.endNode.position.dy + 30,
      );
      // 构建带拐点的连线路径
      final path = Path()
        ..moveTo(startCenter.dx, startCenter.dy)
        ..lineTo(startCenter.dx + 80, startCenter.dy)
        ..lineTo(startCenter.dx + 80, endCenter.dy)
        ..lineTo(endCenter.dx, endCenter.dy);
      canvas.drawPath(path, linkPaint);
      // 绘制箭头
      _drawArrow(canvas, endCenter.dx, endCenter.dy, endCenter.dx - 10, endCenter.dy, linkPaint);
    }

    // 绘制节点
    final nodeBgPaint = Paint()..color = Colors.white;
    final nodeBorderPaint = Paint()
      ..color = Colors.blue.shade300
      ..strokeWidth = 1.5
      ..style = PaintingStyle.stroke;
    final textPainter = TextPainter(textDirection: TextDirection.ltr);

    for (var node in nodes) {
      final nodeRect = Rect.fromLTWH(
        node.position.dx,
        node.position.dy,
        100,
        60,
      );
      // 画节点背景和边框
      canvas.drawRRect(RRect.fromRectAndRadius(nodeRect, Radius.circular(8)), nodeBgPaint);
      canvas.drawRRect(RRect.fromRectAndRadius(nodeRect, Radius.circular(8)), nodeBorderPaint);
      // 画节点文字
      textPainter.text = TextSpan(
        text: node.text,
        style: TextStyle(color: Colors.black87, fontSize: 14),
      );
      textPainter.layout();
      textPainter.paint(
        canvas,
        Offset(
          node.position.dx + (100 - textPainter.width) / 2,
          node.position.dy + (60 - textPainter.height) / 2,
        ),
      );
    }
  }

  void _drawArrow(Canvas canvas, double x1, double y1, double x2, double y2, Paint paint) {
    final arrowLen = 8.0;
    final angle = atan2(y2 - y1, x2 - x1);
    // 画箭头主线
    canvas.drawLine(Offset(x1, y1), Offset(x2, y2), paint);
    // 画箭头两侧
    canvas.drawLine(
      Offset(x2, y2),
      Offset(x2 - arrowLen * cos(angle - pi/6), y2 - arrowLen * sin(angle - pi/6)),
      paint,
    );
    canvas.drawLine(
      Offset(x2, y2),
      Offset(x2 - arrowLen * cos(angle + pi/6), y2 - arrowLen * sin(angle + pi/6)),
      paint,
    );
  }

  @override
  bool shouldRepaint(covariant MindMapPainter oldDelegate) {
    return nodes != oldDelegate.nodes || links != oldDelegate.links;
  }
}

// 定义节点和链接数据类
class Node {
  String text;
  Offset position;
  Node({required this.text, required this.position});
}

class Link {
  Node startNode;
  Node endNode;
  Link({required this.startNode, required this.endNode});
}

2. 用专门的思维导图包:flutter_mind_map

这个包原生支持思维导图结构,能自定义节点样式、连线样式(包括线条类型、箭头、颜色),还支持拖拽、缩放等交互。如果你的需求不需要极端自定义,这个包能快速上手,节省开发时间。

3. 改造GraphView实现自定义

你之前用GraphView觉得无法自定义,其实它支持扩展:

  • 自定义节点:用Node.nodeWidget()包裹你自己写的Widget作为节点UI
  • 自定义连线:继承EdgePainter,重写paint方法绘制你想要的连线样式,然后在GraphView的edgePainter参数中指定这个自定义Painter。

内容的提问来源于stack exchange,提问作者JoseO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 10:50:16