I'm trying to create a simple widget so that when the user presses the screen, a circle appears at that position. I have a CustomPaint widget wrapped by a Listener widget like this:
new Listener(
onPointerDown: down,
child: new CustomPaint(
painter: painter,
size: Size.infinite,
),
)
The problem is that the pointer down events are supplied in global coordinates, and the painting is done in coordinates local to the CustomPaint widget. How should I convert these two coordinate systems?
This page says I can use the RenderBox.globalToLocal method but then how do I get the RenderBox of the CustomPaint widget?
You don't necessarily have to wrap the listener in a widget. You can also use a GlobalKey
to get the RenderObject
.
import 'package:flutter/material.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
State createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> {
GlobalKey _paintKey = new GlobalKey();
Offset _offset;
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('CustomPaint example'),
),
body: new Listener(
onPointerDown: (PointerDownEvent event) {
RenderBox referenceBox = _paintKey.currentContext.findRenderObject();
Offset offset = referenceBox.globalToLocal(event.position);
setState(() {
_offset = offset;
});
},
child: new CustomPaint(
key: _paintKey,
painter: new MyCustomPainter(_offset),
child: new ConstrainedBox(
constraints: new BoxConstraints.expand(),
),
),
),
);
}
}
class MyCustomPainter extends CustomPainter {
final Offset _offset;
MyCustomPainter(this._offset);
@override
void paint(Canvas canvas, Size size) {
if (_offset == null) return;
canvas.drawCircle(_offset, 10.0, new Paint()..color = Colors.blue);
}
@override
bool shouldRepaint(MyCustomPainter other) => other._offset != _offset;
}
OK this worked for me (thanks to help from @mikemimik on gitter):
Wrap the listener in a new custom widget that extends StatelessWidget. The build() method of that widget then gets access to the RenderBox like this:
@override
Widget build(BuildContext context) {
void down(PointerDownEvent evt) {
RenderBox box = context.findRenderObject();
painter.addPos(box.globalToLocal(evt.position));
}
return new Listener(
onPointerDown: down,
child: new CustomPaint(
painter: painter,
size: Size.infinite,
),
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With