我想用flatter构建一个有向图,如下图所示.

enter image description here

推荐答案

你们需要分工合作.

  1. 使层zoom 并移动整个场景,可以使用
  2. 使单个项目可拖动.使用GestureDetector+onPan事件.
  3. 使用CustomPainter在元素之间绘制连接线.我已经做了直接的线条来显示主要逻辑.

…添加额外的逻辑如何添加新项目.

Update: codepen interactive version个由@Maks创建

enter image description here

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Container(
            alignment: Alignment.center,
            child: ItemsScene(),
            decoration: BoxDecoration(
              border: Border.all(
                color: Colors.blueAccent,
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class ItemsScene extends StatefulWidget {
  @override
  _ItemsSceneState createState() => _ItemsSceneState();
}

class _ItemsSceneState extends State<ItemsScene> {
  List<ItemModel> items = [
    ItemModel(offset: Offset(70, 100), text: 'text1'),
    ItemModel(offset: Offset(200, 100), text: 'text2'),
    ItemModel(offset: Offset(200, 230), text: 'text3'),
  ];

  Function onDragStart(int index) => (x, y) {
        setState(() {
          items[index] = items[index].copyWithNewOffset(Offset(x, y));
        });
      };

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        CustomPaint(
          size: Size(double.infinity, double.infinity),
          painter: CurvedPainter(
            offsets: items.map((item) => item.offset).toList(),
          ),
        ),
        ..._buildItems()
      ],
    );
  }

  List<Widget> _buildItems() {
    final res = <Widget>[];
    items.asMap().forEach((ind, item) {
      res.add(_Item(
        onDragStart: onDragStart(ind),
        offset: item.offset,
        text: item.text,
      ));
    });

    return res;
  }
}

class _Item extends StatelessWidget {
  _Item({
    Key key,
    this.offset,
    this.onDragStart,
    this.text,
  });

  final double size = 100;
  final Offset offset;
  final Function onDragStart;
  final String text;

  _handleDrag(details) {
    print(details);
    var x = details.globalPosition.dx;
    var y = details.globalPosition.dy;
    onDragStart(x, y);
  }

  @override
  Widget build(BuildContext context) {
    return Positioned(
      left: offset.dx - size / 2,
      top: offset.dy - size / 2,
      child: GestureDetector(
        onPanStart: _handleDrag,
        onPanUpdate: _handleDrag,
        child: Container(
          width: size,
          height: size,
          child: Text(text),
          decoration: BoxDecoration(
            color: Colors.white,
            border: Border.all(
              color: Colors.blueAccent,
            ),
          ),
        ),
      ),
    );
  }
}

class CurvedPainter extends CustomPainter {
  CurvedPainter({this.offsets});

  final List<Offset> offsets;

  @override
  void paint(Canvas canvas, Size size) {
    if (offsets.length > 1) {
      offsets.asMap().forEach((index, offset) {
        if (index == 0) return;
        canvas.drawLine(
          offsets[index - 1],
          offsets[index],
          Paint()
            ..color = Colors.red
            ..strokeWidth = 2,
        );
      });
    }
  }

  @override
  bool shouldRepaint(CurvedPainter oldDelegate) => true;
}

class ItemModel {
  ItemModel({this.offset, this.text});

  final Offset offset;
  final String text;

  ItemModel copyWithNewOffset(Offset offset) {
    return ItemModel(offset: offset, text: text);
  }
}

Dart相关问答推荐

Flutter tabview刷新问题

Flutter 中的with关键字

在polymer和dart中将内容标签渲染为模板的一部分

如何在flutter中使用rootBundle加载图片?

如何在 Dart 中等待单元测试中的异步设置?

如何使用文本小部件设置多行文本?

Flutter:将照片或图像显示为模态弹出窗口

IOS中Webview Flutter字体太小

替换 Flutter 中的片段等小部件

如何在Flatter中的屏幕中心创建选项卡栏?

如何在 Dart 中获取数字的长度?

如何在图像内的任意点上旋转图像?

Flutter判断变量是否为 NaN

如何在 Dart 中使用 char 类型?

Dart:你如何让 Future 等待 Stream?

如何在 Dart 中以正确的方式重定向和重新加载?

dart - 数字格式

如何使异步 Dart 调用同步?

如何展平flatten列表?

Dart 中的全局变量