From 8f34ca20cae3ac238ab19854942da05bbc68d9cd Mon Sep 17 00:00:00 2001 From: yim Date: Thu, 10 Jul 2025 11:17:13 +0800 Subject: [PATCH] Fix the hitTest issue of reversed SliverMainAxisGroup. (#171073) Fixes: #170999 Fixes: #171121 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- .../lib/src/rendering/sliver_group.dart | 15 +++++++--- .../widgets/sliver_main_axis_group_test.dart | 28 +++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/rendering/sliver_group.dart b/packages/flutter/lib/src/rendering/sliver_group.dart index f10415f1b60..855136773be 100644 --- a/packages/flutter/lib/src/rendering/sliver_group.dart +++ b/packages/flutter/lib/src/rendering/sliver_group.dart @@ -246,10 +246,17 @@ class RenderSliverMainAxisGroup extends RenderSliver @override double childMainAxisPosition(RenderSliver child) { - final Offset paintOffset = (child.parentData! as SliverPhysicalParentData).paintOffset; - return switch (constraints.axis) { - Axis.horizontal => paintOffset.dx, - Axis.vertical => paintOffset.dy, + final SliverPhysicalParentData childParentData = child.parentData! as SliverPhysicalParentData; + return switch (applyGrowthDirectionToAxisDirection( + child.constraints.axisDirection, + child.constraints.growthDirection, + )) { + AxisDirection.down => childParentData.paintOffset.dy, + AxisDirection.right => childParentData.paintOffset.dx, + AxisDirection.up => + geometry!.paintExtent - child.geometry!.paintExtent - childParentData.paintOffset.dy, + AxisDirection.left => + geometry!.paintExtent - child.geometry!.paintExtent - childParentData.paintOffset.dx, }; } diff --git a/packages/flutter/test/widgets/sliver_main_axis_group_test.dart b/packages/flutter/test/widgets/sliver_main_axis_group_test.dart index 2910c130c10..85af01198e3 100644 --- a/packages/flutter/test/widgets/sliver_main_axis_group_test.dart +++ b/packages/flutter/test/widgets/sliver_main_axis_group_test.dart @@ -1063,6 +1063,34 @@ void main() { expect(tester.takeException(), isNull); }); + testWidgets('SliverMainAxisGroup reverse hitTest', (WidgetTester tester) async { + bool onTapCalled = false; + await tester.pumpWidget( + _buildSliverMainAxisGroup( + reverse: true, + viewportHeight: 70, + slivers: [ + SliverToBoxAdapter( + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + onTapCalled = true; + }, + child: const SizedBox(height: 50), + ), + ), + const SliverToBoxAdapter(child: SizedBox(height: 20)), + ], + ), + ); + await tester.tapAt(const Offset(0, 10)); + await tester.pumpAndSettle(); + expect(onTapCalled, isFalse); + await tester.tapAt(const Offset(0, 69)); + await tester.pumpAndSettle(); + expect(onTapCalled, isTrue); + }); + testWidgets('SliverMainAxisGroup with center', (WidgetTester tester) async { final ScrollController controller = ScrollController(); addTearDown(controller.dispose);