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

Flutter GraphView点击节点新增子节点及升序排列问题求解

问题分析

原有代码出现随机添加子节点的核心问题有3个:

  • 新增节点的add()方法中使用r.nextInt(graph.nodeCount())随机选取父节点,完全没有关联当前点击的节点
  • 点击添加按钮时没有传递当前节点的标识,无法定位需要新增子节点的目标父节点
  • 节点ID使用随机数生成,既可能出现ID重复,也无法满足节点升序排列的要求,且每次点击仅新增1个节点,不符合需求。
具体修改方案
  1. 新增自增的节点ID计数器,初始值从现有最大节点ID+1开始,保证后续新增节点ID连续递增
  2. 调整rectangleWidget方法,接收当前节点的完整Node对象而非仅ID值,点击添加按钮时将当前节点作为参数传入新增方法
  3. 重写新增逻辑:接收父节点参数,每次点击添加按钮时生成2个连续ID的新节点,绑定到当前点击的父节点下
  4. 移除新增逻辑中随机选取父节点、随机生成节点ID的错误代码
修正后完整代码
import 'package:flutter/material.dart';
import 'package:graphview/GraphView.dart';

class MyGraphView extends StatefulWidget {
  const MyGraphView({Key? key}) : super(key: key);

  @override
  _MyGraphViewState createState() => _MyGraphViewState();
}

class _MyGraphViewState extends State<MyGraphView> {
  // 移除无用的Random实例,新增自增ID计数器,初始值从初始节点最大值+1开始
  int currentMaxId = 3;
  final Graph graph = Graph()..isTree = true;
  BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration();

  @override
  void initState() {
    final node1 = Node.Id(1);
    final node2 = Node.Id(2);
    final node3 = Node.Id(3);
    graph.addEdge(node1, node2);
    graph.addEdge(node1, node3, paint: Paint());
    builder
      ..siblingSeparation = (50)
      ..levelSeparation = (50)
      ..subtreeSeparation = (50)
      // 同层节点按添加顺序(即ID升序)排列
      ..orientation = (BuchheimWalkerConfiguration.ORIENTATION_TOP_BOTTOM);
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Center(
        child: Scaffold(
          appBar: AppBar(title: const Text("GraphView Example"),),
          body: Column(
            mainAxisSize: MainAxisSize.max,
            crossAxisAlignment: CrossAxisAlignment.end,
            mainAxisAlignment: MainAxisAlignment.end,
            children: [
              Expanded(
                child: InteractiveViewer(
                    constrained: false,
                    boundaryMargin: const EdgeInsets.all(100),
                    minScale: 0.01,
                    maxScale: 5.6,
                    child: GraphView(
                      graph: graph,
                      algorithm: BuchheimWalkerAlgorithm(
                          builder, TreeEdgeRenderer(builder)),
                      paint: Paint()
                        ..color = Colors.green
                        ..strokeWidth = 1
                        ..style = PaintingStyle.stroke,
                      builder: (Node node) {
                        // 直接传入完整node对象,不再只取int值
                        return rectangleWidget(node);
                      },
                    )),
              ),
            ],
          )),
      ),
    );
  }

  Widget rectangleWidget(Node node) {
    int a = node.key?.value as int;
    return InkWell(
      onTap: () {
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: Text("Node $a Clicked"),
          duration: const Duration(seconds: 2, milliseconds: 500),
        ));
      },
      child: Container(
        padding: const EdgeInsets.all(16),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(5),
          boxShadow: const [
            BoxShadow(color: Colors.grey, spreadRadius: 1),
          ],
        ),
        child: Column(
          children: [
            Container(
                padding: const EdgeInsets.all(5),
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(7),
                  boxShadow: const [
                    BoxShadow(color: Colors.green, spreadRadius: 1),
                  ],
                ),
                child: Text('Node $a')
            ),
            const SizedBox(height: 10,),
            GestureDetector(
              onTap: () {
                // 传入当前节点作为父节点
                addChildNodes(node);
              },
              child: Container(
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(5),
                  boxShadow: const [
                    BoxShadow(color: Colors.grey, spreadRadius: 1),
                  ],
                ),
                child: const Icon(Icons.add),
              ),
            ),
          ],
        ),
      ),
    );
  }

  // 重写新增方法,接收父节点参数,一次添加2个升序ID的子节点
  void addChildNodes(Node parentNode){
    // 生成2个连续递增ID的子节点
    for(int i=0; i<2; i++){
      currentMaxId +=1;
      final newNode = Node.Id(currentMaxId);
      graph.addEdge(parentNode, newNode);
    }
    setState(() {});
  }
}
效果说明
  • 点击任意节点的添加按钮,会固定在当前点击节点下新增2个子节点
  • 所有节点ID连续递增,同层节点按ID升序排列,不会出现随机挂载的问题
  • 移除了无用的随机数逻辑,避免ID重复问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 23:21:36