Skip to content

Commit

Permalink
Fixed PositionedTapDetector2's transformation of global to local coor…
Browse files Browse the repository at this point in the history
…ds (#1676)
  • Loading branch information
bramp authored Oct 2, 2023
1 parent 664b3b8 commit c7c6bd0
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 14 deletions.
15 changes: 1 addition & 14 deletions lib/src/misc/private/positioned_tap_detector_2.dart
Original file line number Diff line number Diff line change
Expand Up @@ -164,23 +164,10 @@ class _TapPositionDetectorState extends State<PositionedTapDetector2> {
) async {
_firstTap = null;
if (callback != null) {
callback(_getTapPositions(details));
callback(TapPosition(details.globalPosition, details.localPosition));
}
}

TapPosition _getTapPositions(TapDownDetails details) {
final topLeft = _getWidgetTopLeft();
final global = details.globalPosition;
final relative = topLeft != null ? global - topLeft : null;
return TapPosition(global, relative);
}

Offset? _getWidgetTopLeft() {
final translation =
context.findRenderObject()?.getTransformTo(null).getTranslation();
return translation != null ? Offset(translation.x, translation.y) : null;
}

@override
void dispose() {
_controller.close();
Expand Down
80 changes: 80 additions & 0 deletions test/misc/private/positioned_tap_detector_2_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import 'package:flutter/material.dart';
import 'package:flutter_map/src/misc/private/positioned_tap_detector_2.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
testWidgets('Test tap is detected where expected.', (tester) async {
const screenSize = Size(400, 400);
await tester.binding.setSurfaceSize(screenSize);

// PositionedTapDetector2 fills the full screen.
Offset? lastTap;
final widget = PositionedTapDetector2(
onTap: (position) => lastTap = position.relative,
child: SizedBox(
width: screenSize.width,
height: screenSize.height,
child: Container(
color: Colors.red,
),
),
);

await tester.pumpWidget(widget);

Future<void> tap(Offset pos) async {
lastTap = null;
await tester.tapAt(pos);
expect(lastTap, pos);
}

// Tap top left
await tap(Offset.zero);
// Tap middle
await tap(Offset(screenSize.width / 2, screenSize.height / 2));
// Tap bottom right
await tap(Offset(screenSize.width - 1, screenSize.height - 1));
});

testWidgets('Test tap is detected where expected with scale and offset.',
(tester) async {
const screenSize = Size(400, 400);
await tester.binding.setSurfaceSize(screenSize);

Offset? lastTap;
// The Transform.scale fills the screen, but the PositionedTapDetector2
// occupies the center, with height of 200 (0.5 * 400) and width 400.
final widget = Transform.scale(
scaleY: 0.5,
child: PositionedTapDetector2(
onTap: (position) => lastTap = position.relative,
child: SizedBox(
width: screenSize.width,
height: screenSize.height,
child: Container(
color: Colors.red,
),
),
),
);

await tester.pumpWidget(widget);

// On the screen the PositionedTapDetector2 is actually 400x200, but the
// widget thinks its 400x400.
expect(screenSize, tester.getSize(find.byType(SizedBox)));

Future<void> tap(Offset pos, Offset expected) async {
lastTap = null;
await tester.tapAt(pos);
expect(lastTap, expected);
}

// Tap top left of PositionedTapDetector2 which should be 0,0.
await tap(const Offset(0, 100), Offset.zero);

// Tap bottom right of PositionedTapDetector2
await tap(const Offset(400 - 1, 300 - 0.5),
Offset(screenSize.width - 1, screenSize.height - 1));
});
}

0 comments on commit c7c6bd0

Please sign in to comment.