Unverified Commit d4da441e authored by Kate Lovett's avatar Kate Lovett Committed by GitHub

Apply physics boundary to scrollbar dragging (#72741)

parent 3335bcbe
...@@ -20,6 +20,7 @@ import 'primary_scroll_controller.dart'; ...@@ -20,6 +20,7 @@ import 'primary_scroll_controller.dart';
import 'scroll_controller.dart'; import 'scroll_controller.dart';
import 'scroll_metrics.dart'; import 'scroll_metrics.dart';
import 'scroll_notification.dart'; import 'scroll_notification.dart';
import 'scroll_position.dart';
import 'scrollable.dart'; import 'scrollable.dart';
import 'ticker_provider.dart'; import 'ticker_provider.dart';
...@@ -879,13 +880,18 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv ...@@ -879,13 +880,18 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
void _updateScrollPosition(double primaryDelta) { void _updateScrollPosition(double primaryDelta) {
assert(_currentController != null); assert(_currentController != null);
final ScrollPosition position = _currentController!.position;
// Convert primaryDelta, the amount that the scrollbar moved since the last // Convert primaryDelta, the amount that the scrollbar moved since the last
// time _dragScrollbar was called, into the coordinate space of the scroll // time _updateScrollPosition was called, into the coordinate space of the scroll
// position, and jump to that position. // position, and jump to that position.
final double scrollOffsetLocal = scrollbarPainter.getTrackToScroll(primaryDelta); final double scrollOffsetLocal = scrollbarPainter.getTrackToScroll(primaryDelta);
final double scrollOffsetGlobal = scrollOffsetLocal + _currentController!.position.pixels; final double scrollOffsetGlobal = scrollOffsetLocal + position.pixels;
_currentController!.position.jumpTo(scrollOffsetGlobal); if (scrollOffsetGlobal != position.pixels) {
// Ensure we don't drag into overscroll if the physics do not allow it.
final double physicsAdjustment = position.physics.applyBoundaryConditions(position, scrollOffsetGlobal);
position.jumpTo(scrollOffsetGlobal - physicsAdjustment);
}
} }
void _maybeStartFadeoutTimer() { void _maybeStartFadeoutTimer() {
......
...@@ -752,4 +752,56 @@ void main() { ...@@ -752,4 +752,56 @@ void main() {
), ),
); );
}); });
testWidgets('Scrollbar thumb cannot be dragged into overscroll if the physics do not allow', (WidgetTester tester) async {
final ScrollController scrollController = ScrollController();
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: MediaQuery(
data: const MediaQueryData(),
child: PrimaryScrollController(
controller: scrollController,
child: RawScrollbar(
isAlwaysShown: true,
controller: scrollController,
child: const SingleChildScrollView(
child: SizedBox(width: 4000.0, height: 4000.0)
),
),
),
),
),
);
await tester.pumpAndSettle();
expect(scrollController.offset, 0.0);
expect(
find.byType(RawScrollbar),
paints
..rect(rect: const Rect.fromLTRB(794.0, 0.0, 800.0, 600.0))
..rect(
rect: const Rect.fromLTRB(794.0, 0.0, 800.0, 90.0),
color: const Color(0x66BCBCBC),
),
);
// Try to drag the thumb into overscroll.
const double scrollAmount = -10.0;
final TestGesture dragScrollbarGesture = await tester.startGesture(const Offset(797.0, 45.0));
await tester.pumpAndSettle();
await dragScrollbarGesture.moveBy(const Offset(0.0, scrollAmount));
await tester.pumpAndSettle();
// The physics should not have allowed us to enter overscroll.
expect(scrollController.offset, 0.0);
expect(
find.byType(RawScrollbar),
paints
..rect(rect: const Rect.fromLTRB(794.0, 0.0, 800.0, 600.0))
..rect(
rect: const Rect.fromLTRB(794.0, 0.0, 800.0, 90.0),
color: const Color(0x66BCBCBC),
),
);
});
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment