mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Fix Scrollbar thumb drag behavior on desktop. (#111250)
This commit is contained in:
parent
f4c2ace95f
commit
ff6aa928aa
@ -1447,6 +1447,7 @@ class RawScrollbar extends StatefulWidget {
|
||||
/// scrollbar track.
|
||||
class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProviderStateMixin<T> {
|
||||
Offset? _dragScrollbarAxisOffset;
|
||||
late double? _thumbPress;
|
||||
ScrollController? _currentController;
|
||||
Timer? _fadeoutTimer;
|
||||
late AnimationController _fadeoutAnimationController;
|
||||
@ -1785,6 +1786,9 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
_fadeoutTimer?.cancel();
|
||||
_fadeoutAnimationController.forward();
|
||||
_dragScrollbarAxisOffset = localPosition;
|
||||
_thumbPress = direction == Axis.vertical
|
||||
? localPosition.dy - scrollbarPainter._thumbOffset
|
||||
: localPosition.dx - scrollbarPainter._thumbOffset;
|
||||
}
|
||||
|
||||
/// Handler called when a currently active long press gesture moves.
|
||||
@ -1802,10 +1806,28 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
if (direction == null) {
|
||||
return;
|
||||
}
|
||||
_updateScrollPosition(localPosition);
|
||||
switch (position.axisDirection) {
|
||||
case AxisDirection.up:
|
||||
case AxisDirection.down:
|
||||
if (_canDragThumb(_dragScrollbarAxisOffset!.dy, position.viewportDimension, _thumbPress!)) {
|
||||
_updateScrollPosition(localPosition);
|
||||
}
|
||||
break;
|
||||
case AxisDirection.left:
|
||||
case AxisDirection.right:
|
||||
if (_canDragThumb(_dragScrollbarAxisOffset!.dx, position.viewportDimension, _thumbPress!)) {
|
||||
_updateScrollPosition(localPosition);
|
||||
}
|
||||
break;
|
||||
}
|
||||
_dragScrollbarAxisOffset = localPosition;
|
||||
}
|
||||
|
||||
bool _canDragThumb(double dragOffset, double viewport, double thumbPress) {
|
||||
return dragOffset >= thumbPress
|
||||
&& dragOffset <= viewport - (scrollbarPainter._thumbExtent - thumbPress);
|
||||
}
|
||||
|
||||
/// Handler called when a long press has ended.
|
||||
@protected
|
||||
@mustCallSuper
|
||||
|
||||
@ -2717,4 +2717,142 @@ void main() {
|
||||
|
||||
expect(scrollController.offset, 0.0);
|
||||
});
|
||||
|
||||
testWidgets('Scrollbar thumb can only be dragged from long press point', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/107765
|
||||
|
||||
final ScrollController scrollController = ScrollController();
|
||||
final UniqueKey uniqueKey = UniqueKey();
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: MediaQuery(
|
||||
data: const MediaQueryData(),
|
||||
child: ScrollConfiguration(
|
||||
behavior: const ScrollBehavior().copyWith(
|
||||
scrollbars: false,
|
||||
),
|
||||
child: PrimaryScrollController(
|
||||
controller: scrollController,
|
||||
child: RawScrollbar(
|
||||
isAlwaysShown: true,
|
||||
controller: scrollController,
|
||||
child: CustomScrollView(
|
||||
primary: true,
|
||||
slivers: <Widget>[
|
||||
SliverToBoxAdapter(
|
||||
child: Container(
|
||||
height: 600.0,
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
key: uniqueKey,
|
||||
child: Container(
|
||||
height: 600.0,
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: Container(
|
||||
height: 600.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, 200.0),
|
||||
color: const Color(0x66BCBCBC),
|
||||
),
|
||||
);
|
||||
|
||||
// Long press on the thumb in the center and drag down to the bottom.
|
||||
const double scrollAmount = 400.0;
|
||||
final TestGesture dragScrollbarGesture = await tester.startGesture(const Offset(797.0, 100.0));
|
||||
await tester.pumpAndSettle();
|
||||
await dragScrollbarGesture.moveBy(const Offset(0.0, scrollAmount));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Drag down past the long press point.
|
||||
await dragScrollbarGesture.moveBy(const Offset(0.0, 100));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Drag up without reaching press point on the thumb.
|
||||
await dragScrollbarGesture.moveBy(const Offset(0.0, -50));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Thumb should not move yet.
|
||||
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, 400.0, 800.0, 600.0),
|
||||
color: const Color(0x66BCBCBC),
|
||||
),
|
||||
);
|
||||
|
||||
// Drag up to reach press point on the thumb.
|
||||
await dragScrollbarGesture.moveBy(const Offset(0.0, -50));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Drag up.
|
||||
await dragScrollbarGesture.moveBy(const Offset(0.0, -300));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Thumb should be moved.
|
||||
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, 100.0, 800.0, 300.0),
|
||||
color: const Color(0x66BCBCBC),
|
||||
),
|
||||
);
|
||||
|
||||
// Drag up to reach the top and exceed the long press point.
|
||||
await dragScrollbarGesture.moveBy(const Offset(0.0, -200));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Drag down to reach the long press point.
|
||||
await dragScrollbarGesture.moveBy(const Offset(0.0, 100));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Thumb should not move yet.
|
||||
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, 200.0),
|
||||
color: const Color(0x66BCBCBC),
|
||||
),
|
||||
);
|
||||
|
||||
// Drag down past the long press point.
|
||||
await dragScrollbarGesture.moveBy(const Offset(0.0, 100));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Thumb should be moved.
|
||||
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, 100.0, 800.0, 300.0),
|
||||
color: const Color(0x66BCBCBC),
|
||||
),
|
||||
);
|
||||
}, variant: TargetPlatformVariant.desktop());
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user