颤振有向图。我可以将CustomPainter类与自定义窗口小部件一起使用吗? [英] Flutter directed graph. Can I use CustomPainter Class with custom widgets?
问题描述
我想像下面的图片一样用抖动来构建有向图。
我不知道从哪里开始。我在互联网上搜索失败。我需要哪种图表?
我尝试使用自定义画家类构建此图形。我不知道如何在自定义画家类中使用自定义小部件。 (例如,旁边有人物图片和文字的rect)。
我只能绘制rect和线条...
缩放和平移我认为我可以使用GestureDetector类来做。
该图应可动态自定义。
您需要拆分任务。
- 制作图层以缩放和移动整个场景,则可以将
GestureDetector窗口小部件与onScale事件+ Transform.scale窗口小部件
(检查zoom_widget包)一起使用。 - 使单个项目可拖动。使用GestureDetector + onPan事件。
- 使用CustomPainter在元素之间绘制连接线。我已经用直线显示了主要逻辑。
..添加了额外的逻辑来添加新项目。
更新:
import'package:flutter / material.dart';
void main()=> runApp(MyApp());
类MyApp扩展了StatelessWidget {
@override
Widget build(BuildContext context){
return MaterialApp(
home:Scaffold(
body :Center(
子项:Container(
对齐方式:Alignment.center,
子项:ItemsScene(),
装饰:BoxDecoration(
边界:Border.all(
颜色:Colors.blueAccent,
),
),
),
),
),
);
}
}
类ItemsScene扩展了StatefulWidget {
@override
_ItemsSceneState createState()=> _ItemsSceneState();
}
class _ItemsSceneState扩展了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'),
];
函数onDragStart(int index)=> (x,y){
setState((){
items [index] = items [index] .copyWithNewOffset(Offset(x,y));
});
};
@override
小部件构建(BuildContext上下文){
return Stack(
children:< Widget> [
CustomPaint(
size :Size(double.infinity,double.infinity),
画家: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,
));
});
返回资源;
}
}
类_Item扩展StatelessWidget {
_Item({
密钥,
this.offset,
this .onDragStart,
this.text,
});
最终双倍大小= 100;
最终偏移量;
final Function onDragStart;
最终字符串文本;
_handleDrag(details){
print(details ;;
var x = details.globalPosition.dx;
var y = details.globalPosition.dy;
onDragStart(x,y);
}
@override
窗口小部件build(BuildContext context){
return Positioned(
left:offset.dx-size / 2,
顶部:offset.dy-大小/ 2,
子对象:GestureDetector(
onPanStart:_handleDrag,
onPanUpdate:_handleDrag,
子对象:容器(
宽度:大小,
高度:大小,
子级:Text(text),
装饰:BoxDecoration(
颜色:Colors.white,
边框:Border.all(
颜色:Colors.blueAccent,
),
),
),
),
);
}
}
类CurvedPainter扩展了CustomPainter {
CurvedPainter({this.offsets});
最终列表< Offset>抵消
@override
void paint(画布画布,大小大小){
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)=>真正;
}
class ItemModel {
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屋!