I'm trying to make a Flutter widget to set a temperature, meant to look like a thermostat knob. I've extended CustomPainter to actually draw this on the screen and now I'm trying to set the grab functionality so the user can rotate it.
I can use a GestureDetector widget to get a callback when the user touches the screen, but I need to know where it is relative to the center of the knob. Unfortunately, the position provided by the GestureDetector is in absolute coordinates while the canvas works relative to the origin of the widget. Is there a way I can convert one of these coordinates to the other?
That means I need either:
1) A way to get the tap position relative to the CustomPainter widget
2) A way to get the absolute position of the CustomPainter widget
I am unable to find an API which can provide either of these. Does such an API exist?
Context: https://github.com/dgp1130/thermo/blob/master/lib/widgets/temp_picker.dart
The way it is currently, rotating the thermostat works, but the "center" of the touch is actually about halfway above the real center because of the height of the app bar.
Thanks
You can convert global coordinates to local coordinates using the RenderBox.globalToLocal
method. To get the RenderBox
, you can call findRenderObject
on the BuildContext
.
--- a/lib/widgets/temp_picker.dart
+++ b/lib/widgets/temp_picker.dart
@@ -41,7 +41,12 @@ class _TempPickerState extends State<TempPicker> {
return new Container(
constraints: new BoxConstraints.expand(),
child: new GestureDetector(
- onPanUpdate: (details) => setState(() => _tapPos = details.globalPosition),
+ onPanUpdate: (details) {
+ setState(() {
+ RenderBox box = context.findRenderObject();
+ _tapPos = box.globalToLocal(details.globalPosition);
+ });
+ },
child: new CustomPaint(
painter: new _TempPainter(
minValue: widget.minValue,
This isn't quite right though, because it could behave unexpectedly when the device rotates and the size of your TempPicker
widget changes. Instead of storing the local offset in _tapPos
, I would recommend that you compute and save the results of getAngleFromPosition
in onPanUpdate
and pass that angle value to your _TempPainter
constructor. That way, the angle will remain unchanged when the screen dimensions change, as long as the user isn't currently touching the screen.
You could use the localposition attribute of TapDownDetails as follows :
GestureDetector(
onTapDown: (details) {
//local position
print(details.localPosition);
//global position
print(details.globalPosition);
},
),
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