From e33eb5b46e591bdb97ee3adbd47aab80122445f3 Mon Sep 17 00:00:00 2001 From: Victor Sanni Date: Mon, 29 Jul 2024 16:02:02 -0700 Subject: [PATCH] Stop CupertinoScrollbar's track from paging the scroll view on tap (#152197) Fixes https://github.com/flutter/flutter/issues/120429 --- .../flutter/lib/src/cupertino/scrollbar.dart | 8 +++ .../flutter/lib/src/widgets/scrollbar.dart | 8 ++- .../test/cupertino/scrollbar_test.dart | 61 ++++++++++++++++++- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/scrollbar.dart b/packages/flutter/lib/src/cupertino/scrollbar.dart index bdedb4e91e5..b1254202741 100644 --- a/packages/flutter/lib/src/cupertino/scrollbar.dart +++ b/packages/flutter/lib/src/cupertino/scrollbar.dart @@ -211,6 +211,14 @@ class _CupertinoScrollbarState extends RawScrollbarState { } } + @override + void handleTrackTapDown(TapDownDetails details) { + // On iOS, tapping the track does not page towards the position of the tap. + if (ScrollConfiguration.of(context).getPlatform(context) != TargetPlatform.iOS) { + super.handleTrackTapDown(details); + } + } + @override void dispose() { _thicknessAnimationController.dispose(); diff --git a/packages/flutter/lib/src/widgets/scrollbar.dart b/packages/flutter/lib/src/widgets/scrollbar.dart index d38339dfaff..ab9867bf6cf 100644 --- a/packages/flutter/lib/src/widgets/scrollbar.dart +++ b/packages/flutter/lib/src/widgets/scrollbar.dart @@ -1799,7 +1799,11 @@ class RawScrollbarState extends State with TickerProv _cachedController = null; } - void _handleTrackTapDown(TapDownDetails details) { + /// Handler called when the track is tapped in order to page in the tapped + /// direction. + @protected + @mustCallSuper + void handleTrackTapDown(TapDownDetails details) { // The Scrollbar should page towards the position of the tap on the track. assert(_debugCheckHasValidScrollPosition()); _cachedController = _effectiveScrollController; @@ -2018,7 +2022,7 @@ class RawScrollbarState extends State with TickerProv customPaintKey: _scrollbarPainterKey, ), (_TrackTapGestureRecognizer instance) { - instance.onTapDown = _handleTrackTapDown; + instance.onTapDown = handleTrackTapDown; }, ); diff --git a/packages/flutter/test/cupertino/scrollbar_test.dart b/packages/flutter/test/cupertino/scrollbar_test.dart index 624b32aa1a8..0b448b166ce 100644 --- a/packages/flutter/test/cupertino/scrollbar_test.dart +++ b/packages/flutter/test/cupertino/scrollbar_test.dart @@ -1017,7 +1017,7 @@ void main() { await tester.pump(kScrollbarFadeDuration); }); - testWidgets('Tapping the track area pages the Scroll View', (WidgetTester tester) async { + testWidgets('Tapping the track area pages the Scroll View except on iOS', (WidgetTester tester) async { final ScrollController scrollController = ScrollController(); addTearDown(scrollController.dispose); await tester.pumpWidget( @@ -1075,7 +1075,64 @@ void main() { rrect: RRect.fromLTRBR(794.0, 3.0, 797.0, 359.4, const Radius.circular(1.5)), ), ); - }); + }, variant: TargetPlatformVariant.all(excluding: {TargetPlatform.iOS})); + + testWidgets('Tapping the track area does not page the Scroll View on iOS', (WidgetTester tester) async { + final ScrollController scrollController = ScrollController(); + addTearDown(scrollController.dispose); + await tester.pumpWidget( + Directionality( + textDirection: TextDirection.ltr, + child: MediaQuery( + data: const MediaQueryData(), + child: CupertinoScrollbar( + thumbVisibility: true, + controller: scrollController, + child: SingleChildScrollView( + controller: scrollController, + child: const SizedBox(width: 1000.0, height: 1000.0), + ), + ), + ), + ), + ); + + await tester.pumpAndSettle(); + expect(scrollController.offset, 0.0); + expect( + find.byType(CupertinoScrollbar), + paints..rrect( + color: _kScrollbarColor.color, + rrect: RRect.fromLTRBR(794.0, 3.0, 797.0, 359.4, const Radius.circular(1.5)), + ), + ); + + // Tap on the track area below the thumb. + await tester.tapAt(const Offset(796.0, 550.0)); + await tester.pumpAndSettle(); + + expect(scrollController.offset, 0.0); + expect( + find.byType(CupertinoScrollbar), + paints..rrect( + color: _kScrollbarColor.color, + rrect: RRect.fromLTRBR(794.0, 3.0, 797.0, 359.4, const Radius.circular(1.5)), + ), + ); + + // Tap on the track area above the thumb. + await tester.tapAt(const Offset(796.0, 50.0)); + await tester.pumpAndSettle(); + + expect(scrollController.offset, 0.0); + expect( + find.byType(CupertinoScrollbar), + paints..rrect( + color: _kScrollbarColor.color, + rrect: RRect.fromLTRBR(794.0, 3.0, 797.0, 359.4, const Radius.circular(1.5)), + ), + ); + }, variant: TargetPlatformVariant.only(TargetPlatform.iOS)); testWidgets('Throw if interactive with the bar when no position attached', (WidgetTester tester) async { final ScrollController scrollController = ScrollController();