Commit 8f92cb71 authored by Kate Lovett's avatar Kate Lovett Committed by Flutter GitHub Bot

Fixing PageScrollPhysics to get along with NestedScrollView (#48457)

parent 6495d377
...@@ -471,19 +471,19 @@ class PageScrollPhysics extends ScrollPhysics { ...@@ -471,19 +471,19 @@ class PageScrollPhysics extends ScrollPhysics {
return PageScrollPhysics(parent: buildParent(ancestor)); return PageScrollPhysics(parent: buildParent(ancestor));
} }
double _getPage(ScrollPosition position) { double _getPage(ScrollMetrics position) {
if (position is _PagePosition) if (position is _PagePosition)
return position.page; return position.page;
return position.pixels / position.viewportDimension; return position.pixels / position.viewportDimension;
} }
double _getPixels(ScrollPosition position, double page) { double _getPixels(ScrollMetrics position, double page) {
if (position is _PagePosition) if (position is _PagePosition)
return position.getPixelsFromPage(page); return position.getPixelsFromPage(page);
return page * position.viewportDimension; return page * position.viewportDimension;
} }
double _getTargetPixels(ScrollPosition position, Tolerance tolerance, double velocity) { double _getTargetPixels(ScrollMetrics position, Tolerance tolerance, double velocity) {
double page = _getPage(position); double page = _getPage(position);
if (velocity < -tolerance.velocity) if (velocity < -tolerance.velocity)
page -= 0.5; page -= 0.5;
...@@ -500,7 +500,7 @@ class PageScrollPhysics extends ScrollPhysics { ...@@ -500,7 +500,7 @@ class PageScrollPhysics extends ScrollPhysics {
(velocity >= 0.0 && position.pixels >= position.maxScrollExtent)) (velocity >= 0.0 && position.pixels >= position.maxScrollExtent))
return super.createBallisticSimulation(position, velocity); return super.createBallisticSimulation(position, velocity);
final Tolerance tolerance = this.tolerance; final Tolerance tolerance = this.tolerance;
final double target = _getTargetPixels(position as ScrollPosition, tolerance, velocity); final double target = _getTargetPixels(position, tolerance, velocity);
if (target != position.pixels) if (target != position.pixels)
return ScrollSpringSimulation(spring, position.pixels, target, velocity, tolerance: tolerance); return ScrollSpringSimulation(spring, position.pixels, target, velocity, tolerance: tolerance);
return null; return null;
......
...@@ -4,16 +4,23 @@ ...@@ -4,16 +4,23 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
class TestScrollPhysics extends ScrollPhysics { class TestScrollPhysics extends ScrollPhysics {
const TestScrollPhysics({ this.name, ScrollPhysics parent }) : super(parent: parent); const TestScrollPhysics({
this.name,
ScrollPhysics parent
}) : super(parent: parent);
final String name; final String name;
@override @override
TestScrollPhysics applyTo(ScrollPhysics ancestor) { TestScrollPhysics applyTo(ScrollPhysics ancestor) {
return TestScrollPhysics(name: name, parent: parent?.applyTo(ancestor) ?? ancestor); return TestScrollPhysics(
name: name,
parent: parent?.applyTo(ancestor) ?? ancestor,
);
} }
TestScrollPhysics get namedParent => parent as TestScrollPhysics; TestScrollPhysics get namedParent => parent as TestScrollPhysics;
...@@ -62,20 +69,30 @@ void main() { ...@@ -62,20 +69,30 @@ void main() {
String types(ScrollPhysics s) => s.parent == null ? '${s.runtimeType}' : '${s.runtimeType} ${types(s.parent)}'; String types(ScrollPhysics s) => s.parent == null ? '${s.runtimeType}' : '${s.runtimeType} ${types(s.parent)}';
expect(types(bounce.applyTo(clamp.applyTo(never.applyTo(always.applyTo(page))))), expect(
'BouncingScrollPhysics ClampingScrollPhysics NeverScrollableScrollPhysics AlwaysScrollableScrollPhysics PageScrollPhysics'); types(bounce.applyTo(clamp.applyTo(never.applyTo(always.applyTo(page))))),
'BouncingScrollPhysics ClampingScrollPhysics NeverScrollableScrollPhysics AlwaysScrollableScrollPhysics PageScrollPhysics',
);
expect(types(clamp.applyTo(never.applyTo(always.applyTo(page.applyTo(bounce))))), expect(
'ClampingScrollPhysics NeverScrollableScrollPhysics AlwaysScrollableScrollPhysics PageScrollPhysics BouncingScrollPhysics'); types(clamp.applyTo(never.applyTo(always.applyTo(page.applyTo(bounce))))),
'ClampingScrollPhysics NeverScrollableScrollPhysics AlwaysScrollableScrollPhysics PageScrollPhysics BouncingScrollPhysics',
);
expect(types(never.applyTo(always.applyTo(page.applyTo(bounce.applyTo(clamp))))), expect(
'NeverScrollableScrollPhysics AlwaysScrollableScrollPhysics PageScrollPhysics BouncingScrollPhysics ClampingScrollPhysics'); types(never.applyTo(always.applyTo(page.applyTo(bounce.applyTo(clamp))))),
'NeverScrollableScrollPhysics AlwaysScrollableScrollPhysics PageScrollPhysics BouncingScrollPhysics ClampingScrollPhysics',
);
expect(types(always.applyTo(page.applyTo(bounce.applyTo(clamp.applyTo(never))))), expect(
'AlwaysScrollableScrollPhysics PageScrollPhysics BouncingScrollPhysics ClampingScrollPhysics NeverScrollableScrollPhysics'); types(always.applyTo(page.applyTo(bounce.applyTo(clamp.applyTo(never))))),
'AlwaysScrollableScrollPhysics PageScrollPhysics BouncingScrollPhysics ClampingScrollPhysics NeverScrollableScrollPhysics',
);
expect(types(page.applyTo(bounce.applyTo(clamp.applyTo(never.applyTo(always))))), expect(
'PageScrollPhysics BouncingScrollPhysics ClampingScrollPhysics NeverScrollableScrollPhysics AlwaysScrollableScrollPhysics'); types(page.applyTo(bounce.applyTo(clamp.applyTo(never.applyTo(always))))),
'PageScrollPhysics BouncingScrollPhysics ClampingScrollPhysics NeverScrollableScrollPhysics AlwaysScrollableScrollPhysics',
);
}); });
group('BouncingScrollPhysics test', () { group('BouncingScrollPhysics test', () {
...@@ -115,7 +132,10 @@ void main() { ...@@ -115,7 +132,10 @@ void main() {
expect(moreOverscrollApplied, lessThan(20.0)); expect(moreOverscrollApplied, lessThan(20.0));
// Scrolling from a more overscrolled position meets more resistance. // Scrolling from a more overscrolled position meets more resistance.
expect(lessOverscrollApplied.abs(), greaterThan(moreOverscrollApplied.abs())); expect(
lessOverscrollApplied.abs(),
greaterThan(moreOverscrollApplied.abs()),
);
}); });
test('easing an overscroll still has resistance', () { test('easing an overscroll still has resistance', () {
...@@ -143,8 +163,14 @@ void main() { ...@@ -143,8 +163,14 @@ void main() {
axisDirection: AxisDirection.down, axisDirection: AxisDirection.down,
); );
expect(physicsUnderTest.applyPhysicsToUserOffset(scrollPosition, 10.0), 10.0); expect(
expect(physicsUnderTest.applyPhysicsToUserOffset(scrollPosition, -10.0), -10.0); physicsUnderTest.applyPhysicsToUserOffset(scrollPosition, 10.0),
10.0,
);
expect(
physicsUnderTest.applyPhysicsToUserOffset(scrollPosition, -10.0),
-10.0,
);
}); });
test('easing an overscroll meets less resistance than tensioning', () { test('easing an overscroll meets less resistance than tensioning', () {
...@@ -222,7 +248,9 @@ void main() { ...@@ -222,7 +248,9 @@ void main() {
// RegExp matcher is required here due to flutter web and flutter mobile generating // RegExp matcher is required here due to flutter web and flutter mobile generating
// slightly different floating point numbers // slightly different floating point numbers
// in Flutter web 0.0 sometimes just appears as 0. or 0 // in Flutter web 0.0 sometimes just appears as 0. or 0
expect(error.toStringDeep(), matches(RegExp( expect(
error.toStringDeep(),
matches(RegExp(
r'''FlutterError r'''FlutterError
ClampingScrollPhysics\.applyBoundaryConditions\(\) was called ClampingScrollPhysics\.applyBoundaryConditions\(\) was called
redundantly\. redundantly\.
...@@ -236,8 +264,33 @@ void main() { ...@@ -236,8 +264,33 @@ void main() {
The position object in question was\: The position object in question was\:
FixedScrollMetrics\(500(\.\d*)?..\[0(\.\d*)?\]..500(\.\d*)?\) FixedScrollMetrics\(500(\.\d*)?..\[0(\.\d*)?\]..500(\.\d*)?\)
''', ''',
multiLine: true, multiLine: true,
))); ))
);
} }
}); });
testWidgets('PageScrollPhysics work with NestedScrollView', (WidgetTester tester) async {
// Regression test for: https://github.com/flutter/flutter/issues/47850
await tester.pumpWidget(Material(
child: Directionality(
textDirection: TextDirection.ltr,
child: NestedScrollView(
physics: const PageScrollPhysics(),
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverToBoxAdapter(child: Container(height: 300, color: Colors.blue)),
];
},
body: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Text('Index $index');
},
itemCount: 100,
),
),
)
));
await tester.fling(find.text('Index 2'), const Offset(0.0, -300.0), 10000.0);
});
} }
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