fix an assertion causes by zero offset pointer scroll (#73016)

This commit is contained in:
xubaolin 2021-01-15 05:59:03 +08:00 committed by GitHub
parent fc25d8b0cc
commit 217cd102bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 7 deletions

View file

@ -629,8 +629,7 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
// Returns the offset that should result from applying [event] to the current
// position, taking min/max scroll extent into account.
double _targetScrollOffsetForPointerScroll(PointerScrollEvent event) {
final double delta = _pointerSignalEventDelta(event);
double _targetScrollOffsetForPointerScroll(double delta) {
return math.min(math.max(position.pixels + delta, position.minScrollExtent),
position.maxScrollExtent);
}
@ -653,9 +652,10 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
if (_physics != null && !_physics!.shouldAcceptUserOffset(position)) {
return;
}
final double targetScrollOffset = _targetScrollOffsetForPointerScroll(event);
final double delta = _pointerSignalEventDelta(event);
final double targetScrollOffset = _targetScrollOffsetForPointerScroll(delta);
// Only express interest in the event if it would actually result in a scroll.
if (targetScrollOffset != position.pixels) {
if (delta != 0.0 && targetScrollOffset != position.pixels) {
GestureBinding.instance!.pointerSignalResolver.register(event, _handlePointerScroll);
}
}
@ -663,9 +663,10 @@ class ScrollableState extends State<Scrollable> with TickerProviderStateMixin, R
void _handlePointerScroll(PointerEvent event) {
assert(event is PointerScrollEvent);
final double targetScrollOffset = _targetScrollOffsetForPointerScroll(event as PointerScrollEvent);
if (targetScrollOffset != position.pixels) {
position.pointerScroll(_pointerSignalEventDelta(event));
final double delta = _pointerSignalEventDelta(event as PointerScrollEvent);
final double targetScrollOffset = _targetScrollOffsetForPointerScroll(delta);
if (delta != 0.0 && targetScrollOffset != position.pixels) {
position.pointerScroll(delta);
}
}

View file

@ -1206,6 +1206,47 @@ void main() {
expect(outerController.position.pixels, 0.0);
expect(innerController.position.pixels, 0.0);
});
// Regression test for https://github.com/flutter/flutter/issues/71949
testWidgets('Zero offset pointer scroll should not trigger an assertion.', (WidgetTester tester) async {
final ScrollController controller = ScrollController();
Widget build(double height) {
return MaterialApp(
home: Scaffold(
body: SizedBox(
width: double.infinity,
height: height,
child: SingleChildScrollView(
controller: controller,
child: const SizedBox(
width: double.infinity,
height: 300.0,
),
),
)
),
);
}
await tester.pumpWidget(build(200.0));
expect(controller.position.pixels, 0.0);
controller.jumpTo(100.0);
expect(controller.position.pixels, 100.0);
// Make the outer constraints larger that the scrollable widget is no longer able to scroll.
await tester.pumpWidget(build(300.0));
expect(controller.position.pixels, 100.0);
expect(controller.position.maxScrollExtent, 0.0);
// Hover over the scroll view and create a zero offset pointer scroll.
final Offset scrollable = tester.getCenter(find.byType(SingleChildScrollView));
final TestPointer testPointer = TestPointer(1, ui.PointerDeviceKind.mouse);
testPointer.hover(scrollable);
await tester.sendEventToBinding(testPointer.scroll(const Offset(0.0, 0.0)));
expect(tester.takeException(), null);
});
}
// ignore: must_be_immutable