Search code examples
flutterdartcustom-painting

Flutter drawing a heart shape with CustomPainter


I'm wondering if anyone has any pointers on how to get started on drawing a heart shape in flutter with CustomPainter. I've managed to draw things like triangles and squares, or a basic circle, but a heart of course has both straight and curved lines.

I have this which draws a triangle, which looks a little like a heart, but don't know how to get the curved lines that a heart requires.

class Heart extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: CustomPaint(
        painter: TrianglePainter(
          strokeColor: Color(0xFFF27788),
          paintingStyle: PaintingStyle.fill,
        ),
        child: Container(
          height: 60 * Dep.hr,
          width: 60 * Dep.hr,
        ),
      ),
    );
  }
}

class TrianglePainter extends CustomPainter {
  final Color strokeColor;
  final PaintingStyle paintingStyle;
  final double strokeWidth;

  TrianglePainter({this.strokeColor, this.strokeWidth = 3, this.paintingStyle = PaintingStyle.stroke});

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..color = strokeColor
      ..strokeWidth = strokeWidth
      ..style = paintingStyle;

    canvas.drawPath(getTrianglePath(size.width, size.height), paint);
  }

  Path getTrianglePath(double x, double y) {
    return Path()
      ..moveTo(y, 0)
      ..lineTo(0, 0)
      ..lineTo(x / 2, y);
  }

  @override
  bool shouldRepaint(TrianglePainter oldDelegate) {
    return oldDelegate.strokeColor != strokeColor ||
        oldDelegate.paintingStyle != paintingStyle ||
        oldDelegate.strokeWidth != strokeWidth;
  }
}

Also it's just a block of colour, but I really need a border around the shape too. This is my expected output, not sure if it's wishful thinking or not.

enter image description here


Solution

  • Try this :

      class HeartWidget extends StatefulWidget {
        @override
        _HeartWidgetState createState() => _HeartWidgetState();
      }
    
      class _HeartWidgetState extends State<HeartWidget> {
        @override
        Widget build(BuildContext context) {
          return Scaffold(
            appBar: AppBar(
              title: Text('Testing'),
            ),
            body: Center(
            child: CustomPaint(
                size: Size(70, 80),
                painter: HeartPainter(),
              ),
            ),
          );
        }
      }
    
      class HeartPainter extends CustomPainter {
        @override
        void paint(Canvas canvas, Size size) {
          // TODO: implement paint
          Paint paint = Paint();
          paint
            ..color = Colors.black
            ..style = PaintingStyle.stroke
            ..strokeCap = StrokeCap.round
            ..strokeWidth = 6;
    
          Paint paint1 = Paint();
          paint1
            ..color = Colors.red
            ..style = PaintingStyle.fill
            ..strokeWidth = 0;
    
          double width = size.width;
          double height = size.height;
    
          Path path = Path();
          path.moveTo(0.5 * width, height * 0.35);
          path.cubicTo(0.2 * width, height * 0.1, -0.25 * width, height * 0.6,
              0.5 * width, height);
          path.moveTo(0.5 * width, height * 0.35);
          path.cubicTo(0.8 * width, height * 0.1, 1.25 * width, height * 0.6,
              0.5 * width, height);
    
          canvas.drawPath(path, paint1);
          canvas.drawPath(path, paint);
        }
    
        @override
        bool shouldRepaint(CustomPainter oldDelegate) {
          return true;
        }
      }
    

    enter image description here