How do I get to tap on a CustomPaint path in Flutter using GestureDetect?

4,371

Solution 1

You have to override the hitTest() method of your KeyPathPainter class:

@override
bool hitTest(Offset position) {
    // _path - is the same one we built in paint() method;
    return _path.contains(position);
}

That will allow GestureDetector to detect taps inside the path instead of the entire CustomPaint container. Though the _path must be closed since there's no way—at least that I know of—to test hits on curves.

Solution 2

Wrapping your paint with a gesture detector should do the work.

 GestureDetector(
    onTapDown: (details) {
         print("${details.globalPosition.dx}");
         print("${details.globalPosition.dy}");
     },
  ),

Solution 3

I came to this from googling an issue I had. My issue was I was just wrapping the Painter in a gesture detector like:

GestureDetector(
      child: CustomPaint(
        painter: CustomPainter(),
      ),

      onTapDown: _handleTapDown,
);

Where the solution was I needed to have a Container with a color, wrapping the Custom Painter, like so:

return GestureDetector(
      child: Container(
        width: 300,
        height: 300,
        color: Colors.white,
        child: CustomPaint(
          painter: CustomPainter(),
        ),
      ),

      onTapDown: _handleTapDown,
);
Share:
4,371
graciax452
Author by

graciax452

Updated on November 21, 2022

Comments

  • graciax452
    graciax452 over 1 year

    I'm very new to flutter and am trying to figure out how to get a gesture detected on a CustomPaint path. I can click on a host of other things but not on paths for some reason... How do I get this to work? My code thus far is below.

    import 'package:flutter/material.dart';
    
    void main() => runApp(MbiraShapes());
    
    class MbiraShapes extends StatefulWidget {
        @override
      _MbiraShapesState createState() => _MbiraShapesState();
    }
    
    class _MbiraShapesState extends State<MbiraShapes>{
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
            title: 'Mbira Shapes',
            home: PathExample());
      }
    }
    
    class PathExample extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return CustomPaint(
          painter: KeyPathPainter(),
        );
      }
    }
    
    class KeyPathPainter extends CustomPainter {
      @override
      void paint(Canvas canvas, Size size) {
        Paint lineDrawer = Paint()
          ..color = Colors.blue
          ..strokeWidth = 8.0;
    
        Path path = Path()
    // Moves to starting point
          ..moveTo(50, 50)
          //draw lines passing through xc, yc to end at x,y
          ..quadraticBezierTo(77, 370, 50, 750)
          ..quadraticBezierTo(100, 775, 150, 750)
          ..quadraticBezierTo(110, 440, 75, 50);
        //close shape from last point
        path.close();
        canvas.drawPath(path, lineDrawer);
    
        Path path2 = Path()
    // Moves to starting point
          ..moveTo(250, 50)
          //draw lines passing through xc, yc to end at x,y
          ..quadraticBezierTo(280, 350, 270, 675)
          ..quadraticBezierTo(290, 750, 350, 750)
          ..quadraticBezierTo(365, 710, 345, 600)
          ..quadraticBezierTo(320, 450, 270, 50);
        //close shape from last point
        path2.close();
        canvas.drawPath(path2, lineDrawer);
      }
    
      @override
      bool shouldRepaint(CustomPainter oldDelegate) => true;
    }

    I tried the snippet below with GestureDetector but it does not work. I tried a Listener but get no response for onPointerDown, only for onPointerMove, but I need a tap action, not a move action.

    @override
      Widget build(BuildContext context) {
    
        return Scaffold(
          appBar: AppBar(
      
            title: Text("widget.title)"),
          ),
          
          body: Center(
            child: GestureDetector(
              child: CustomPaint(
                painter: KeyPathPainter(),
                child: Container()),
              onTap: () {
                print("tapped the key");
              },
            ),
          ),
        );
      }

    I just want to tap a key and get a response, it will be a sound in the end but for now, I'm just trying to figure out how to get the onTap to work.