Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get Tap Position Relative to Widget

Tags:

flutter

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

like image 266
Douglas Parker Avatar asked May 03 '17 02:05

Douglas Parker


2 Answers

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.

like image 77
Collin Jackson Avatar answered Oct 13 '22 00:10

Collin Jackson


You could use the localposition attribute of TapDownDetails as follows :

GestureDetector(
  onTapDown: (details) {
       //local position
       print(details.localPosition);
       //global position 
       print(details.globalPosition);
  },
),
like image 24
Amine Dakhli Avatar answered Oct 13 '22 00:10

Amine Dakhli