diff --git a/packages/flutter/lib/src/cupertino/segmented_control.dart b/packages/flutter/lib/src/cupertino/segmented_control.dart index 82cb6dbd9b7..467087ba2b5 100644 --- a/packages/flutter/lib/src/cupertino/segmented_control.dart +++ b/packages/flutter/lib/src/cupertino/segmented_control.dart @@ -718,13 +718,12 @@ class _RenderSegmentedControl extends RenderBox while (child != null) { final _SegmentedControlContainerBoxParentData childParentData = child.parentData as _SegmentedControlContainerBoxParentData; if (childParentData.surroundingRect.contains(position)) { - final Offset center = (Offset.zero & child.size).center; - return result.addWithRawTransform( - transform: MatrixUtils.forceToPoint(center), - position: center, - hitTest: (BoxHitTestResult result, Offset position) { - assert(position == center); - return child.hitTest(result, position: center); + return result.addWithPaintOffset( + offset: childParentData.offset, + position: position, + hitTest: (BoxHitTestResult result, Offset localOffset) { + assert(localOffset == position - childParentData.offset); + return child.hitTest(result, position: localOffset); }, ); } diff --git a/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart b/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart index e34c4946f33..2e3ed47c390 100644 --- a/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart +++ b/packages/flutter/lib/src/cupertino/sliding_segmented_control.dart @@ -1025,13 +1025,12 @@ class _RenderSegmentedControl extends RenderBox final _SegmentedControlContainerBoxParentData childParentData = child.parentData as _SegmentedControlContainerBoxParentData; if ((childParentData.offset & child.size).contains(position)) { - final Offset center = (Offset.zero & child.size).center; - return result.addWithRawTransform( - transform: MatrixUtils.forceToPoint(center), - position: center, - hitTest: (BoxHitTestResult result, Offset position) { - assert(position == center); - return child.hitTest(result, position: center); + return result.addWithPaintOffset( + offset: childParentData.offset, + position: position, + hitTest: (BoxHitTestResult result, Offset localOffset) { + assert(localOffset == position - childParentData.offset); + return child.hitTest(result, position: localOffset); }, ); } diff --git a/packages/flutter/test/cupertino/segmented_control_test.dart b/packages/flutter/test/cupertino/segmented_control_test.dart index bdf1927a579..cdbd9719a1d 100644 --- a/packages/flutter/test/cupertino/segmented_control_test.dart +++ b/packages/flutter/test/cupertino/segmented_control_test.dart @@ -926,6 +926,46 @@ void main() { expect(sharedValue, 0); }); + testWidgets('Hit-tests report accurate local position in segments', (WidgetTester tester) async { + final Map children = {}; + TapDownDetails tapDownDetails; + children[0] = GestureDetector( + behavior: HitTestBehavior.opaque, + onTapDown: (TapDownDetails details) { tapDownDetails = details; }, + child: const SizedBox(width: 200, height: 200), + ); + children[1] = const Text('Child 2'); + + int sharedValue = 1; + + await tester.pumpWidget( + StatefulBuilder( + builder: (BuildContext context, StateSetter setState) { + return boilerplate( + child: CupertinoSegmentedControl( + key: const ValueKey('Segmented Control'), + children: children, + onValueChanged: (int newValue) { + setState(() { + sharedValue = newValue; + }); + }, + groupValue: sharedValue, + ), + ); + }, + ), + ); + + expect(sharedValue, 1); + + final Offset segment0GlobalOffset = tester.getTopLeft(find.byWidget(children[0])); + await tester.tapAt(segment0GlobalOffset + const Offset(7, 11)); + + expect(tapDownDetails.localPosition, const Offset(7, 11)); + expect(tapDownDetails.globalPosition, segment0GlobalOffset + const Offset(7, 11)); + }); + testWidgets( 'Segment still hittable with a child that has no hitbox', (WidgetTester tester) async { diff --git a/packages/flutter/test/cupertino/sliding_segmented_control_test.dart b/packages/flutter/test/cupertino/sliding_segmented_control_test.dart index 1c133021628..42929e8025c 100644 --- a/packages/flutter/test/cupertino/sliding_segmented_control_test.dart +++ b/packages/flutter/test/cupertino/sliding_segmented_control_test.dart @@ -783,6 +783,38 @@ void main() { expect(groupValue, 1); }); + testWidgets('Hit-tests report accurate local position in segments', (WidgetTester tester) async { + final Map children = {}; + TapDownDetails tapDownDetails; + children[0] = GestureDetector( + behavior: HitTestBehavior.opaque, + onTapDown: (TapDownDetails details) { tapDownDetails = details; }, + child: const SizedBox(width: 200, height: 200), + ); + children[1] = const Text('Child 2'); + + await tester.pumpWidget( + boilerplate( + builder: (BuildContext context) { + return CupertinoSlidingSegmentedControl( + key: const ValueKey('Segmented Control'), + children: children, + groupValue: groupValue, + onValueChanged: defaultCallback, + ); + }, + ), + ); + + expect(groupValue, 0); + + final Offset segment0GlobalOffset = tester.getTopLeft(find.byWidget(children[0])); + await tester.tapAt(segment0GlobalOffset + const Offset(7, 11)); + + expect(tapDownDetails.localPosition, const Offset(7, 11)); + expect(tapDownDetails.globalPosition, segment0GlobalOffset + const Offset(7, 11)); + }); + testWidgets('Thumb animation is correct when the selected segment changes', (WidgetTester tester) async { await tester.pumpWidget(setupSimpleSegmentedControl());