Apply physics boundary to scrollbar dragging (#72741)

This commit is contained in:
Kate Lovett 2020-12-21 18:24:03 -06:00 committed by GitHub
parent 3335bcbe40
commit d4da441e53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 61 additions and 3 deletions

View File

@ -20,6 +20,7 @@ import 'primary_scroll_controller.dart';
import 'scroll_controller.dart';
import 'scroll_metrics.dart';
import 'scroll_notification.dart';
import 'scroll_position.dart';
import 'scrollable.dart';
import 'ticker_provider.dart';
@ -879,13 +880,18 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
void _updateScrollPosition(double primaryDelta) {
assert(_currentController != null);
final ScrollPosition position = _currentController!.position;
// 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.
final double scrollOffsetLocal = scrollbarPainter.getTrackToScroll(primaryDelta);
final double scrollOffsetGlobal = scrollOffsetLocal + _currentController!.position.pixels;
_currentController!.position.jumpTo(scrollOffsetGlobal);
final double scrollOffsetGlobal = scrollOffsetLocal + position.pixels;
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() {

View File

@ -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),
),
);
});
}