mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Fix scrollbar dragging into overscroll when not allowed (#90634)
This commit is contained in:
parent
37a47015be
commit
3aed0b671f
@ -16,6 +16,7 @@ import 'gesture_detector.dart';
|
||||
import 'media_query.dart';
|
||||
import 'notification_listener.dart';
|
||||
import 'primary_scroll_controller.dart';
|
||||
import 'scroll_configuration.dart';
|
||||
import 'scroll_controller.dart';
|
||||
import 'scroll_metrics.dart';
|
||||
import 'scroll_notification.dart';
|
||||
@ -1367,7 +1368,24 @@ class RawScrollbarState<T extends RawScrollbar> extends State<T> with TickerProv
|
||||
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);
|
||||
double newPosition = scrollOffsetGlobal - physicsAdjustment;
|
||||
|
||||
// The physics may allow overscroll when actually *scrolling*, but
|
||||
// dragging on the scrollbar does not always allow us to enter overscroll.
|
||||
switch(ScrollConfiguration.of(context).getPlatform(context)) {
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.linux:
|
||||
case TargetPlatform.macOS:
|
||||
case TargetPlatform.windows:
|
||||
newPosition = newPosition.clamp(0.0, position.maxScrollExtent);
|
||||
break;
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.android:
|
||||
// We can only drag the scrollbar into overscroll on mobile
|
||||
// platforms, and only if the physics allow it.
|
||||
break;
|
||||
}
|
||||
position.jumpTo(newPosition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1025,6 +1025,139 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
testWidgets('Scrollbar thumb cannot be dragged into overscroll if the platform does not allow it', (WidgetTester tester) async {
|
||||
final ScrollController scrollController = ScrollController();
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: MediaQuery(
|
||||
data: const MediaQueryData(),
|
||||
child: ScrollConfiguration(
|
||||
// Don't apply a scrollbar automatically for this test.
|
||||
behavior: const ScrollBehavior().copyWith(
|
||||
scrollbars: false,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
),
|
||||
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 platform drag handling 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),
|
||||
),
|
||||
);
|
||||
|
||||
await dragScrollbarGesture.up();
|
||||
await tester.pumpAndSettle();
|
||||
}, variant: const TargetPlatformVariant(<TargetPlatform>{
|
||||
TargetPlatform.macOS,
|
||||
TargetPlatform.linux,
|
||||
TargetPlatform.windows,
|
||||
TargetPlatform.fuchsia,
|
||||
}));
|
||||
|
||||
testWidgets('Scrollbar thumb can be dragged into overscroll if the platform allows it', (WidgetTester tester) async {
|
||||
final ScrollController scrollController = ScrollController();
|
||||
await tester.pumpWidget(
|
||||
Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: MediaQuery(
|
||||
data: const MediaQueryData(),
|
||||
child: ScrollConfiguration(
|
||||
// Don't apply a scrollbar automatically for this test.
|
||||
behavior: const ScrollBehavior().copyWith(
|
||||
scrollbars: false,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
),
|
||||
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 platform drag handling should have allowed us to enter overscroll.
|
||||
expect(scrollController.offset, lessThan(-66.0));
|
||||
expect(
|
||||
find.byType(RawScrollbar),
|
||||
paints
|
||||
..rect(rect: const Rect.fromLTRB(794.0, 0.0, 800.0, 600.0))
|
||||
..rect(
|
||||
// The size of the scrollbar thumb shrinks when overscrolling
|
||||
rect: const Rect.fromLTRB(794.0, 0.0, 800.0, 80.0),
|
||||
color: const Color(0x66BCBCBC),
|
||||
),
|
||||
);
|
||||
|
||||
await dragScrollbarGesture.up();
|
||||
await tester.pumpAndSettle();
|
||||
}, variant: const TargetPlatformVariant(<TargetPlatform>{
|
||||
TargetPlatform.android,
|
||||
TargetPlatform.iOS,
|
||||
}));
|
||||
|
||||
// Regression test for https://github.com/flutter/flutter/issues/66444
|
||||
testWidgets("RawScrollbar doesn't show when scroll the inner scrollable widget", (WidgetTester tester) async {
|
||||
final GlobalKey key1 = GlobalKey();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user