I couldn't find a way of doing it as you wanted, but I've been able to do it with a different approach. In this example I'm wrapping the CustomPaint
with a MouseRegion
(because I'm testing it with flutter web, you could recreate it for mobiles with InkWell
or GestureDetector
) and then I'm checking if the localPosition of the mouse in inside the rect of the TextPainter
. I'm creating the TextPainter
outside CustomPainter
because I wanted the full canvas to be twice the TextPainter
's size.
class GestureText extends StatefulWidget {
const GestureText(this.text, {required this.style, this.maxWidth, Key? key})
: super(key: key);
final String text;
final TextStyle style;
final double? maxWidth;
@override
_GestureTextState createState() => _GestureTextState();
}
class _GestureTextState extends State<GestureText> {
Offset? mousePosition;
@override
Widget build(BuildContext context) {
final TextPainter textPainter = TextPainter(
text: TextSpan(
text: widget.text,
style: widget.style,
),
textDirection: TextDirection.ltr,
)..layout(maxWidth: widget.maxWidth ?? double.infinity);
return Container(
child: MouseRegion(
onHover: (e){
setState(() {
mousePosition = e.localPosition;
});
},
onExit: (e){
setState(() {
mousePosition = null;
});
},
child: CustomPaint(
size: Size(textPainter.size.width*2, textPainter.size.width*2),
painter: GestureTextPainter(textPainter, mousePosition),
),
),
);
}
}
class GestureTextPainter extends CustomPainter {
const GestureTextPainter(this.textPainter, this.mousePosition);
final TextPainter textPainter;
final Offset? mousePosition;
@override
void paint(Canvas canvas, Size size) {
final textOffset = Offset(size.width/2 - textPainter.width/2, size.height/2 - textPainter.height/2);
// So that the text is in the middle of the canvas
final textRect = Rect.fromLTWH(textOffset.dx, textOffset.dy, textPainter.width, textPainter.height);
if(mousePosition != null && textRect.contains(mousePosition!)){
canvas.drawRect(textRect, Paint()..color=Colors.amber);
}
textPainter.paint(canvas, textOffset);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}