我想用颤振构建一个如下图所示的有向图。我不知道从哪里开始。我在互联网上搜索没有成功。这种图需要哪些算法?我尝试使用自定义画家类构建此图。我不知道如何在自定义画家类中使用自定义小部件。(例如,旁边有人物图片和文字的矩形)。我只能画矩形和线条......缩放和平移我想我可以用 GestureDetector 类来做。该图应该是可动态定制的。
问问题
3055 次
2 回答
22
您需要拆分任务。
- 使图层缩放和移动整个场景,您可以将 GestureDetector 小部件与 onScale 事件 + Transform.scale 小部件一起使用(检查 zoom_widget 包)。
- 使单个项目可拖动。使用 GestureDetector + onPan 事件。
- 使用 CustomPainter 在元素之间绘制连接线。我做了直线来展示主要逻辑。
.. 添加额外的逻辑如何添加新项目。
更新: @maks创建的codepen 交互式版本
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);
}
}
于 2020-01-21T11:42:49.660 回答
0
CustomPainter 似乎有点矫枉过正。使用堆栈。您需要首先计算每个节点或连接的位置和大小,然后使用 Positioned 小部件放置它们。
于 2020-01-20T13:15:19.473 回答