Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to draw custom shape in flutter and drag that shape around?

Tags:

flutter

dart

At the moment I can draw rectangles using CustomPainter. Below the code inside the paint method of my CustomPainter.

for (var rectPoints in rectangles) {
  paint.color = rectPoints.color;
  paint.strokeWidth = rectPoints.strokeWidth;
  if (rectPoints.selected != null && rectPoints.selected == true) {
    paint.color = Colors.black45;
  }
  var rect = Rect.fromLTWH(
      rectPoints.startPoint.dx,
      rectPoints.startPoint.dy,
      rectPoints.endPoint.dx - rectPoints.startPoint.dx,
      rectPoints.endPoint.dy - rectPoints.startPoint.dy);
  canvas.drawRect(rect, paint);
}

var rect = Rect.fromLTWH(startPoint.dx, startPoint.dy,
    endPoint.dx - startPoint.dx, endPoint.dy - startPoint.dy);
canvas.drawRect(rect, paint);

A rectangle is a custom object with startPoint, endPoint and some other properties needed to draw that specific rectangle. Now I want to select a rectangle and re-position it. Any help would be appreciated. Thanks

like image 745
Danish Jamil Avatar asked Dec 07 '22 11:12

Danish Jamil


2 Answers

You'll need to track the state of the rectangles' positions independent of the canvas drawing. The easiest way to do that is to use a StatefulWidget. You'll also need to use a GestureDetector to capture the pan events. Then you can wire up the gesture details to the position of the rectangles and call the painter to redraw everything.

Here's a simple app that shows how to do it with one rectangle. Should be straightforward to expand it to handle multiple ones.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Draggable Custom Painter',
      home: Scaffold(
        body: CustomPainterDraggable(),
      ),
    );
  }
}

class CustomPainterDraggable extends StatefulWidget {
  @override
  _CustomPainterDraggableState createState() => _CustomPainterDraggableState();
}

class _CustomPainterDraggableState extends State<CustomPainterDraggable> {
  var xPos = 0.0;
  var yPos = 0.0;
  final width = 100.0;
  final height = 100.0;
  bool _dragging = false;

  /// Is the point (x, y) inside the rect?
  bool _insideRect(double x, double y) =>
      x >= xPos && x <= xPos + width && y >= yPos && y <= yPos + height;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanStart: (details) => _dragging = _insideRect(
        details.globalPosition.dx,
        details.globalPosition.dy,
      ),
      onPanEnd: (details) {
        _dragging = false;
      },
      onPanUpdate: (details) {
        if (_dragging) {
          setState(() {
            xPos += details.delta.dx;
            yPos += details.delta.dy;
          });
        }
      },
      child: Container(
        color: Colors.white,
        child: CustomPaint(
          painter: RectanglePainter(Rect.fromLTWH(xPos, yPos, width, height)),
          child: Container(),
        ),
      ),
    );
  }
}

class RectanglePainter extends CustomPainter {
  RectanglePainter(this.rect);
  final Rect rect;

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawRect(rect, Paint());
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}
like image 75
Matt S. Avatar answered May 20 '23 22:05

Matt S.


I have developed a library called touchable for the purpose of adding gesture callbacks to each individual shape you draw on the canvas. You can draw your shapes and add onPanUpdate or onTapDown callbacks to drag your shape around.

Here's what you can do to detect touch and drag on your circle.

Here's a small example taken directly from the pub dev site :

Wrap your CustomPaint widget with CanvasTouchDetector. It takes a builder function as argument that expects your CustomPaint widget as shown below.

import 'package:touchable/touchable.dart';


CanvasTouchDetector(
    builder: (context) => 
        CustomPaint(
            painter: MyPainter(context)
        )
)

Inside your CustomPainter class's paint method , create and use the TouchyCanvas object (using the context obtained from the CanvasTouchDetector and canvas) to draw your shape and you can give gesture callbacks like onPanUpdate , onTapDown here to detect your drag events.

var myCanvas = TouchyCanvas(context,canvas);
myCanvas.drawRect( rect , Paint() , onPanUpdate: (detail){
    //This callback runs when you drag this rectangle. Details of the location can be got from the detail object.
    //Do stuff here. Probably change your state and animate
});
like image 29
Natesh bhat Avatar answered May 20 '23 23:05

Natesh bhat