flutterpaintcustom-painting

GestureDetector on painted triangles in circle


I'm trying to handle taps for three painted "quartercirlces" using the CustomPaint widget. I've tried adding GestureDetectors around the QuarterCirclePainter class. Even tried using using a GestureRecognizer for the TextSpan without any success. Tried wrapping it in containers wrapped in gestureDetectors. Looked at similar posts about adding GestureDetectors around the CustomPaint, but none of them seems to work in this case. How can this be achieved?

class CategoryCircle extends StatelessWidget {
  final Color color;
  final double startAngle;
  final String category;
  final Offset textOffset;
  CategoryCircle({this.color, this.startAngle, this.category, this.textOffset});

  Widget build(BuildContext context) {
    FocusScope.of(context).nextFocus();
    return FractionallySizedBox(
      widthFactor: 1,
      heightFactor: 1,
      child: Center(
        child: CustomPaint(
            painter: QuarterCirclePainter(
                context: context,
                color: color,
                startAngle: startAngle,
                sweepAngle: math.pi * 2 / 3,
                text: category,
                textOffset: textOffset)),
      ),
    );
  }
}

class QuarterCirclePainter extends CustomPainter {
  final BuildContext context;
  final Color color;
  final double startAngle;
  final double sweepAngle;
  final String text;
  final Offset textOffset;

  const QuarterCirclePainter(
      {this.context,
      this.color,
      this.startAngle,
      this.sweepAngle,
      this.text,
      this.textOffset});

  @override
  void paint(Canvas canvas, Size size) {
    Offset center = Offset(size.width / 2, size.height / 2);
    Rect rect = Rect.fromCircle(center: center, radius: 130);
    Path path = Path()
      // set the "current point"
      ..moveTo(center.dx, center.dy)
      ..arcTo(rect, startAngle, (math.pi * 2) / 3, false);
    canvas.drawPath(path, Paint()..color = color);
    TextSpan span = new TextSpan(
        style: GoogleFonts.overpass(
            textStyle: TextStyle(fontSize: 22, fontWeight: FontWeight.bold)),
        text: text);
    TextPainter tp = new TextPainter(
        text: span,
        textAlign: TextAlign.center,
        textDirection: TextDirection.ltr);
    tp.layout();
    tp.paint(canvas, textOffset);
  }

  @override
  bool shouldRepaint(QuarterCirclePainter oldDelegate) {
    return false;
  }
}

enter image description here


Solution

  • I made a CustomClipper with what you did in the QuarterCirclePainter, it looks like this:

    class QuaterCircleClipper extends CustomClipper<Path>{
      double startAngle, sweepAngle;
    
      QuaterCircleClipper({@required this.startAngle, @required this.sweepAngle});
    
    
      @override
      Path getClip(Size size){
        Offset center = Offset(size.width / 2, size.height / 2);
        Rect rect = Rect.fromCircle(center: center, radius: 130);
        Path path = Path()
          // set the "current point"
          ..moveTo(center.dx, center.dy)
          ..arcTo(rect, startAngle, (math.pi * 2) / 3, false);
          return path;
      }
    
      @override
      bool shouldReclip(oldCliper) => false;
    }
    

    And used a ClipPath with the above CustomClipper as clipper to wrap a GestureDetector which has a blue Container as its child

    Container(
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.height,
      child: AspectRatio(
        aspectRatio: 1,
        child: ClipPath(
          clipper: QuaterCircleClipper(startAngle: 0, sweepAngle: 120),
          child: GestureDetector(
            onTap: (){showDialog(context: context, builder: (_) => AlertDialog(content: Text("Tap Detected"),));},
            child: Container(
              color: Colors.blueAccent,
            )
          ),
        ),
      )
    ),
    

    enter image description here