Unverified Commit eef4220a authored by Dan Field's avatar Dan Field Committed by GitHub

Make large jumpTo recommend deferred loading (#64271)

parent 8489d460
...@@ -145,6 +145,24 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics { ...@@ -145,6 +145,24 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
double get maxScrollExtent => _maxScrollExtent; double get maxScrollExtent => _maxScrollExtent;
double _maxScrollExtent; double _maxScrollExtent;
/// The additional velocity added for a [forcePixels] change in a single
/// frame.
///
/// This value is used by [recommendDeferredLoading] in addition to the
/// [activity]'s [ScrollActivity.velocity] to ask the [physics] whether or
/// not to defer loading. It accounts for the fact that a [forcePixels] call
/// may involve a [ScrollActivity] with 0 velocity, but the scrollable is
/// still instantaneously moving from its current position to a potentially
/// very far position, and which is of interest to callers of
/// [recommendDeferredLoading].
///
/// For example, if a scrollable is currently at 5000 pixels, and we [jumpTo]
/// 0 to get back to the top of the list, we would have an implied velocity of
/// -5000 and an `activity.velocity` of 0. The jump may be going past a
/// number of resource intensive widgets which should avoid doing work if the
/// position jumps past them.
double _impliedVelocity = 0;
@override @override
double get pixels => _pixels; double get pixels => _pixels;
double _pixels; double _pixels;
...@@ -343,8 +361,13 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics { ...@@ -343,8 +361,13 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
@protected @protected
void forcePixels(double value) { void forcePixels(double value) {
assert(pixels != null); assert(pixels != null);
assert(value != null);
_impliedVelocity = value - _pixels;
_pixels = value; _pixels = value;
notifyListeners(); notifyListeners();
SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) {
_impliedVelocity = 0;
});
} }
/// Called whenever scrolling ends, to store the current scroll offset in a /// Called whenever scrolling ends, to store the current scroll offset in a
...@@ -834,7 +857,12 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics { ...@@ -834,7 +857,12 @@ abstract class ScrollPosition extends ViewportOffset with ScrollMetrics {
assert(context != null); assert(context != null);
assert(activity != null); assert(activity != null);
assert(activity.velocity != null); assert(activity.velocity != null);
return physics.recommendDeferredLoading(activity.velocity, copyWith(), context); assert(_impliedVelocity != null);
return physics.recommendDeferredLoading(
activity.velocity + _impliedVelocity,
copyWith(),
context,
);
} }
@override @override
......
...@@ -229,4 +229,41 @@ void main() { ...@@ -229,4 +229,41 @@ void main() {
); );
expect(controller.position.pixels, equals(0.0)); expect(controller.position.pixels, equals(0.0));
}); });
testWidgets('jumpTo recomends deferred loading', (WidgetTester tester) async {
int loadedWithDeferral = 0;
int buildCount = 0;
const double height = 500;
await tester.pumpWidget(MaterialApp(
home: ListView.builder(
itemBuilder: (BuildContext context, int index) {
buildCount += 1;
if (Scrollable.recommendDeferredLoadingForContext(context)) {
loadedWithDeferral += 1;
}
return const SizedBox(height: height);
},
),
));
// The two visible on screen should have loaded without deferral.
expect(buildCount, 2);
expect(loadedWithDeferral, 0);
final ScrollPosition position = tester.state<ScrollableState>(find.byType(Scrollable)).position;
position.jumpTo(height * 100);
await tester.pump();
// All but the first two that were loaded normally should have gotten a
// recommendation to defer.
expect(buildCount, 102);
expect(loadedWithDeferral, 100);
position.jumpTo(height * 102);
await tester.pump();
// The smaller jump should not have recommended deferral.
expect(buildCount, 104);
expect(loadedWithDeferral, 100);
});
} }
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