[flutter (플루터 앱 개발)] Flutter Canvas 그리기 예제 - (6) 드래그로 Canvas 내 Object 이동시키기

Flutter Canvas 드래그로 Object 이동시키기

이 포스팅에서는 Flutter Canvas에서 드래그를 통해 객체(Object)를 이동시키는 방법을 설명합니다. 사용자는 특정 객체를 터치하고 드래그하여 원하는 위치로 이동시킬 수 있습니다.


1. Node 클래스

먼저, 이동 가능한 객체를 나타내는 Node 클래스를 정의합니다.


 

class Node {

  String id;

  String name;

  double x;

  double y;

 

  Node(this.id, this.name, this.x, this.y);

}

 

 

 

  • id: 객체의 고유 식별자.
  • name: 객체에 표시될 텍스트.
  • x, y: Canvas에서의 좌표.

2. DraggablePainter 클래스

Canvas에 배경, 그리드, 객체를 그리는 CustomPainter를 정의합니다.

class DraggablePainter extends CustomPainter {
  static const gridWidth = 50.0;
  static const gridHeight = 50.0;

  final double offsetX;
  final double offsetY;
  final List<Node> nodeList;

  DraggablePainter(this.nodeList, this.offsetX, this.offsetY);

  void _drawBackground(Canvas canvas, Size size) {
    final paint = Paint()..color = Colors.white70;
    canvas.drawRect(Rect.fromLTWH(0, 0, size.width, size.height), paint);
  }

  void _drawGrid(Canvas canvas, Size size) {
    final paint = Paint()..color = Colors.grey;
    for (double x = 0; x < size.width; x += gridWidth) {
      canvas.drawLine(Offset(x, 0), Offset(x, size.height), paint);
    }
    for (double y = 0; y < size.height; y += gridHeight) {
      canvas.drawLine(Offset(0, y), Offset(size.width, y), paint);
    }
  }

  void _drawNodes(Canvas canvas) {
    final paint = Paint()..color = Colors.amber;
    const textStyle = TextStyle(color: Colors.black, fontSize: 14);
    const radius = 30.0;

    for (final node in nodeList) {
      final center = Offset(node.x, node.y);
      canvas.drawCircle(center, radius, paint);
      _drawText(canvas, node.x, node.y, node.name, textStyle);
    }
  }

  void _drawText(Canvas canvas, double x, double y, String text, TextStyle style) {
    final textSpan = TextSpan(text: text, style: style);
    final textPainter = TextPainter(
      text: textSpan,
      textDirection: TextDirection.ltr,
    )..layout();
    final offset = Offset(x - textPainter.width / 2, y - textPainter.height / 2);
    textPainter.paint(canvas, offset);
  }

  @override
  void paint(Canvas canvas, Size size) {
    canvas.save();
    canvas.translate(offsetX, offsetY);

    _drawBackground(canvas, size);
    _drawGrid(canvas, size);
    _drawNodes(canvas);

    canvas.restore();
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}
 

 


3. GestureDetector를 활용한 드래그 이벤트 처리

사용자의 드래그 이벤트를 처리하여 객체를 이동시킵니다.

class DraggableObjectPageState extends State<DraggableObjectPage> {

  final List<Node> nodeList = [

    Node("1", "Node\n1", 150.0, 180.0),

    Node("2", "Node\n2", 220.0, 40.0),

    Node("3", "Node\n3", 380.0, 240.0),

    Node("4", "Node\n4", 640.0, 190.0),

    Node("5", "Node\n5", 480.0, 350.0),

  ];

 

  double offsetX = 0.0;

  double offsetY = 0.0;

  double preX = 0.0;

  double preY = 0.0;

  Node? currentNode;

 

  Node? _getNodeAt(double x, double y) {

    const radius = 30.0;

    for (final node in nodeList) {

      final distance = (node.x - x).abs() + (node.y - y).abs();

      if (distance <= radius) {

        return node;

      }

    }

    return null;

  }

 

  void _handlePanDown(DragDownDetails details) {

    final x = details.localPosition.dx - offsetX;

    final y = details.localPosition.dy - offsetY;

 

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

    currentNode = _getNodeAt(x, y);

    preX = details.localPosition.dx;

    preY = details.localPosition.dy;

  }

 

  void _handlePanUpdate(DragUpdateDetails details) {

    final dx = details.localPosition.dx - preX;

    final dy = details.localPosition.dy - preY;

 

    if (currentNode != null) {

      setState(() {

        currentNode!.x += dx;

        currentNode!.y += dy;

      });

    } else {

      setState(() {

        offsetX += dx;

        offsetY += dy;

      });

    }

 

    preX = details.localPosition.dx;

    preY = details.localPosition.dy;

  }

 

  @override

  Widget build(BuildContext context) {

    return Scaffold(

      body: GestureDetector(

        onPanDown: _handlePanDown,

        onPanUpdate: _handlePanUpdate,

        child: CustomPaint(

          painter: DraggablePainter(nodeList, offsetX, offsetY),

          child: Container(),

        ),

      ),

    );

  }

}

 

 

결론

이 코드를 통해 사용자는 Canvas 내부의 특정 객체를 드래그로 이동시킬 수 있습니다. GestureDetectorCustomPainter를 적절히 활용하여 직관적인 인터페이스를 제공합니다. 추가적으로, 객체와 Canvas 전체의 동시 이동도 처리할 수 있습니다.

 

 

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED