Flutter : 사용자 정의 페인트에서 모양 드래그 앤 드롭
소개
이 게시물에서는 Flutter CustomPaint Widget을 사용하여 사용자 대화형 Drag & Drop을 구현하는 방법을 공유하고 싶습니다. 플러터와 다트가 제공하는 것만 사용할 것이기 때문에
no packages need to be installed
가 있습니다. 자, 뛰어들자!1. 셰이프 개체 데이터가 포함된 StatefulWidget
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool isDown = false;
double x = 0.0;
double y = 0.0;
int? targetId;
Map<int, Map<String, double>> pathList = {
1: {"x": 100, "y": 100, "r": 50, "color": 0},
2: {"x": 200, "y": 200, "r": 50, "color": 1},
3: {"x": 300, "y": 300, "r": 50, "color": 2},
};
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(child: Text('dummy text'))
);
}
}
먼저 사용자 상호 작용에 반응하도록 하려면
StatefulWidget
가 필요합니다.2. 포함할 위젯
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: GestureDetector(
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.grey,
child: CustomPaint(
foregroundPainter:
ShapePainter(down: isDown, x: x, y: y, pathList: pathList),
size: Size(MediaQuery.of(context).size.width,
MediaQuery.of(context).size.height),
)),
) // This trailing comma makes auto-formatting nicer for build methods.
);
}
이제 위젯 트리를 채워야 합니다.
3. 사용자 상호 작용 캡처
// util function
bool isInObject(Map<String, double> data, double dx, double dy) {
Path _tempPath = Path()
..addOval(Rect.fromCircle(
center: Offset(data['x']!, data['y']!), radius: data['r']!));
return _tempPath.contains(Offset(dx, dy));
}
// event handler
void _down(DragStartDetails details) {
setState(() {
isDown = true;
x = details.localPosition.dx;
y = details.localPosition.dy;
});
}
void _up() {
setState(() {
isDown = false;
targetId = null;
});
}
void _move(DragUpdateDetails details) {
if (isDown) {
setState(() {
x += details.delta.dx;
y += details.delta.dy;
targetId ??= pathList.keys
.firstWhereOrNull((_id) => isInObject(pathList[_id]!, x, y));
if (targetId != null) {
pathList = {
...pathList,
targetId!: {...pathList[targetId!]!, 'x': x, 'y': y}
};
}
});
}
}
// map event handler to pan event
...
body: GestureDetector(
onPanStart: (details) {
_down(details);
},
onPanEnd: (details) {
_up();
},
onPanUpdate: (details) {
_move(details);
},
...
다음은 이벤트 핸들러 등록입니다.
GestureDetector
에서 팬 이벤트는 드래그 앤 드롭용입니다.4. CustomPaint 및 CustomPainter를 사용하여 그리기
class ShapePainter extends CustomPainter {
final colors = [Colors.red, Colors.yellow, Colors.lightBlue];
Path path = Path();
Paint _paint = Paint()
..color = Colors.red
..strokeWidth = 5
..strokeCap = StrokeCap.round;
final bool down;
final double x;
final double y;
Map<int, Map<String, double>> pathList;
ShapePainter({
required this.down,
required this.x,
required this.y,
required this.pathList,
});
@override
void paint(Canvas canvas, Size size) {
for (var pathData in pathList.values) {
_paint = _paint..color = colors[pathData['color']! as int];
path = Path()
..addOval(Rect.fromCircle(
center: Offset(pathData['x']!, pathData['y']!),
radius: pathData['r']!));
canvas.drawPath(path, _paint);
}
}
@override
bool shouldRepaint(ShapePainter oldDelegate) => down;
}
ShapePainter는 페인트 방법을 소유한 것입니다. 별다른 로직은 없고, 위의 위젯이 준 데이터를 그냥 그립니다.
shouldRepaint
는 사용자가 터치하거나 마우스를 눌렀을 때 항상 호출되므로 사용자가 작업 중일 때만 업데이트를 수행할 수 있습니다.결론
나는 일반적으로 캔버스에 정말 관심이 있습니다. Flutter CustomPainter를 사용하여 Drag & Drop을 구현하려는 분들께 도움이 되었으면 합니다.
건배!
Reference
이 문제에 관하여(Flutter : 사용자 정의 페인트에서 모양 드래그 앤 드롭), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/swimmingkiim/flutter-drag-drop-shapes-in-custompaint-3ngj텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)