颤振有向图.我可以将 CustomPainter 类与自定义小部件一起使用吗? [英] Flutter directed graph. Can I use CustomPainter Class with custom widgets?
问题描述
我想用颤振构建一个如下图所示的有向图.我不知道从哪里开始.我在互联网上搜索没有成功.这种图需要哪些算法?我尝试使用自定义画家类构建此图.我不知道如何在自定义画家类中使用自定义小部件.(例如,旁边有人物图片和文字的矩形).我只能画矩形和线条......缩放和平移我认为我可以使用 GestureDetector 类.图表应该可以动态定制.
你需要拆分任务.
- 使图层缩放和移动整个场景,您可以使用带有 onScale 事件 + Transform.scale 小部件的 GestureDetector 小部件,(检查 zoom_widget 包).
- 使单个项目可拖动.使用 GestureDetector + onPan 事件.
- 使用 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.
- 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).
- Make the single item draggable. Use GestureDetector + onPan events.
- 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屋!