我正在做一个让二部图相关的项目,用户可以拖动图内的任一节点到另外的节点上创建一条边。
现在的做法是让 CustomPaint 的 child 中包含 Draggable 列和 DragTarge 列,然后希望在拖动完成后绘制一条两个组件之间的连线。
目前的问题是,我现在可以实现拖动后绘制一条线,但是在拖动完成后显示出来,只有在热重载之后才会将线条绘制出来。然后当我拖动到另外一个组件时,之前已经存在的连线不能够保存下来。
请问我应该如何实现这两个功能呢?
画布实现
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';
import 'package:get_demo/pages/canvas/painter/painter3.dart';
class Canvas3 extends StatefulWidget {
const Canvas3({Key? key}) : super(key: key);
@override
_Canvas3State createState() => _Canvas3State();
}
class _Canvas3State extends State<Canvas3> {
var start_offset = ValueNotifier(Offset.zero);
var end_offset = ValueNotifier(Offset.zero);
var key1 = GlobalKey();
var key2 = GlobalKey();
var key3 = GlobalKey();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
width: 500,
height: 500,
color: Colors.red.shade100,
// 创建画布
child: CustomPaint(
child: Column(
children: [
_buildItems(),
],
),
foregroundPainter: Painter3(start_offset, end_offset),
),
),
);
}
// 创建内容
Row _buildItems() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Draggable 是左侧列
Draggable(
child: Container(
key: key1,
width: 100,
height: 100,
child: Image.asset('assets/images/Pig.png'),
decoration: BoxDecoration(color: Colors.pink),
),
data: 1,
// 拖动反馈
feedback: Container(
width: 100,
height: 100,
decoration: BoxDecoration(color: Colors.lightGreen),
),
// 当开始拖动时计算当前盒子的坐标中心点
onDragStarted: () {
var box = key1.currentContext!.findRenderObject() as RenderBox;
var x = box.localToGlobal(Offset.zero).dx + box.size.width / 2;
var y = box.localToGlobal(Offset.zero).dy - box.size.height / 2;
start_offset.value = Offset(x, y);
},
),
// DragTarget 是右侧列
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
DragTarget(
builder: (context, c, r) => Container(
key: key2,
width: 100,
height: 100,
child: Image.asset('assets/images/Chicken.png'),
decoration: BoxDecoration(color: Colors.green),
),
// 接收到数据获取当前盒子的坐标中心点
onAccept: (_) {
var box = key2.currentContext!.findRenderObject() as RenderBox;
var x = box.localToGlobal(Offset.zero).dx + box.size.width / 2;
var y = box.localToGlobal(Offset.zero).dy - box.size.height / 2;
end_offset.value = Offset(x, y);
},
),
SizedBox(
height: 50,
),
DragTarget(
builder: (context, c, r) => Container(
key: key3,
width: 100,
height: 100,
child: Image.asset('assets/images/Horse.png'),
decoration: BoxDecoration(color: Colors.green),
),
onAccept: (_) {
var box = key3.currentContext!.findRenderObject() as RenderBox;
var x = box.localToGlobal(Offset.zero).dx + box.size.width / 2;
var y = box.localToGlobal(Offset.zero).dy - box.size.height / 2;
end_offset.value = Offset(x, y);
},
),
],
)
],
);
}
}
画笔绘制实现
// ignore_for_file: prefer_final_fields, prefer_typing_uninitialized_variables
import 'package:flutter/material.dart';
class Painter3 extends CustomPainter {
// 绘制起点
var _start;
// 绘制终点
var _end;
Painter3(this._start, this._end);
@override
void paint(Canvas canvas, Size size) {
// 画笔属性
var _paint = Paint()
..color = Colors.black
..strokeWidth = 5
..strokeCap = StrokeCap.round;
// 绘制线条
canvas.clipRect(Offset.zero & size);
canvas.drawLine(_start.value, _end.value, _paint);
}
@override
bool shouldRepaint(Painter3 oldDelegate) {
return true;
}
}
经过一番折腾自己解决了。
解决过程如下:
希望这个问题以及解决思路对后来的同学有所帮助。