颤振有向图.我可以将 CustomPainter 类与自定义小部件一起使用吗? [英] Flutter directed graph. Can I use CustomPainter Class with custom widgets?

查看:10
本文介绍了颤振有向图.我可以将 CustomPainter 类与自定义小部件一起使用吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用颤振构建一个如下图所示的有向图.我不知道从哪里开始.我在互联网上搜索没有成功.这种图需要哪些算法?我尝试使用自定义画家类构建此图.我不知道如何在自定义画家类中使用自定义小部件.(例如,旁边有人物图片和文字的矩形).我只能画矩形和线条......缩放和平移我认为我可以使用 GestureDetector 类.图表应该可以动态定制.

解决方案

你需要拆分任务.

  1. 使图层缩放和移动整个场景,您可以使用带有 onScale 事件 + Transform.scale 小部件的 GestureDetector 小部件,(检查 zoom_widget 包).
  2. 使单个项目可拖动.使用 GestureDetector + onPan 事件.
  3. 使用 CustomPainter 绘制元素之间的连接线.我已经做了直线来展示主要逻辑.

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

更新:

import 'package:flutter/material.dart';无效的主要()=>运行应用程序(我的应用程序());MyApp 类扩展 StatelessWidget {@覆盖小部件构建(BuildContext 上下文){返回材料应用程序(家:脚手架(身体:中心(孩子:容器(对齐:对齐中心,孩子:ItemsScene(),装饰:盒子装饰(边框:边框.all(颜色:Colors.blueAccent,),),),),),);}}类 ItemsScene 扩展 StatefulWidget {@覆盖_ItemsSceneState createState() =>_ItemsSceneState();}类 _ItemsSceneState 扩展状态<ItemsScene>{列表<ItemModel>项目= [ItemModel(offset: Offset(70, 100), text: 'text1'),ItemModel(offset: Offset(200, 100), text: 'text2'),ItemModel(offset: Offset(200, 230), text: 'text3'),];函数 onDragStart(int index) =>(x, y) {设置状态((){items[index] = items[index].copyWithNewOffset(Offset(x, y));});};@覆盖小部件构建(BuildContext 上下文){返回堆栈(孩子们:<小部件>[自定义油漆(尺寸:尺寸(双无限,双无限),画家:曲线画家(偏移量:items.map((item) => item.offset).toList(),),),..._buildItems()],);}列表<小部件>_buildItems() {最终 res = <Widget>[];items.asMap().forEach((ind, item) {res.add(_Item(onDragStart: onDragStart(ind),偏移量:item.offset,文本:item.text,));});返回资源;}}类 _Item 扩展 StatelessWidget {_物品({钥匙钥匙,this.offset,this.onDragStart,this.text,});最终双倍大小 = 100;最终偏移量;最终函数 onDragStart;最终字符串文本;_handleDrag(详情){打印(详细信息);var x = details.globalPosition.dx;var y = details.globalPosition.dy;onDragStart(x, y);}@覆盖小部件构建(BuildContext 上下文){返回定位(左:offset.dx - 大小/2,顶部:offset.dy - 大小/2,孩子:手势检测器(onPanStart: _handleDrag,onPanUpdate: _handleDrag,孩子:容器(宽度:尺寸,高度:尺寸,孩子:文本(文本),装饰:盒子装饰(颜色:颜色.白色,边框:边框.all(颜色:Colors.blueAccent,),),),),);}}类 CurvedPainter 扩展 CustomPainter {CurvedPainter({this.offsets});最终列表<偏移>偏移量;@覆盖无效油漆(帆布画布,尺寸大小){if (offsets.length > 1) {offsets.asMap().forEach((index, offset) {如果(索引 == 0)返回;画布.drawLine(偏移量[索引 - 1],偏移量[索引],画()..color = 颜色.red..strokeWidth = 2,);});}}@覆盖bool shouldRepaint(CurvedPainter oldDelegate) =>真的;}类项目模型 {ItemModel({this.offset, this.text});最终偏移量;最终字符串文本;ItemModel copyWithNewOffset(Offset offset) {return ItemModel(offset: offset, text: text);}}

I want to build a directed graph like in the picture below with flutter. I dont know where to start. I searched at internet without success. Which algorihms do I need for this kind of graph? I tried to build this graph with custom painter class. I dont know how to use custom widgets inside custom painter class. (for example a rect with a picture of person and text beside). I only was able to draw rect and lines... Zoom and pan I thought I can do with GestureDetector class. The graph should be customizable dynamicly.

解决方案

You need to split your tasks.

  1. Make the layer to zoom and move whole scene, you can use the GestureDetector widget with onScale events + Transform.scale widget, (check zoom_widget package).
  2. Make the single item draggable. Use GestureDetector + onPan events.
  3. Draw connection lines between element using CustomPainter. I've made direct lines to show the main logic.

.. add extra logic how to add new items.

Update: codepen interactive version created by @maks

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);
  }
}

这篇关于颤振有向图.我可以将 CustomPainter 类与自定义小部件一起使用吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆