Skip to content

Commit 09ad9f3

Browse files
authored
Document ScrollPhysics invariant requiring ballistic motion (flutter#120400)
Fixes flutter#120341. The scroll protocol makes an important assumption about the behavior of ScrollPhysics implementations, and this requirement hasn't been clearly documented. Add documentation for it. Parts of the text are modelled on similar language at StatelessWidget.build and StatefulWidget.build. It does feel a bit uncomfortable to juxtapose this description of a required invariant with three issues where the framework doesn't satisfy it. Fortunately two of them apply by default only in uncommon cases: flutter#120340 macOS touchpad flinging, and flutter#109675 never. The third is flutter#120338, affecting default scrolling on Android and other non-Apple platforms. I'll send a PR to fix that shortly, and another for flutter#109675. As discussed at flutter#120338, it's quite possible we'll remove this invariant in the future. But that's been attempted before, and is complicated: the invariant is a useful one. Removing it would almost certainly involve a breaking change for ScrollPhysics subclasses. So I think even if we had an immediate plan to remove it, we'd need some kind of documentation for it, if only to explain the breaking change.
1 parent e00241a commit 09ad9f3

File tree

1 file changed

+22
-0
lines changed

1 file changed

+22
-0
lines changed

packages/flutter/lib/src/widgets/scroll_physics.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,28 @@ class ScrollPhysics {
365365
/// The given `position` is only valid during this method call. Do not keep a
366366
/// reference to it to use later, as the values may update, may not update, or
367367
/// may update to reflect an entirely unrelated scrollable.
368+
///
369+
/// This method can potentially be called in every frame, even in the middle
370+
/// of what the user perceives as a single ballistic scroll. For example, in
371+
/// a [ListView] when previously off-screen items come into view and are laid
372+
/// out, this method may be called with a new [ScrollMetrics.maxScrollExtent].
373+
/// The method implementation should ensure that when the same ballistic
374+
/// scroll motion is still intended, these calls have no side effects on the
375+
/// physics beyond continuing that motion.
376+
///
377+
/// Generally this is ensured by having the [Simulation] conform to a physical
378+
/// metaphor of a particle in ballistic flight, where the forces on the
379+
/// particle depend only on its position, velocity, and environment, and not
380+
/// on the current time or any internal state. This means that the
381+
/// time-derivative of [Simulation.dx] should be possible to write
382+
/// mathematically as a function purely of the values of [Simulation.x],
383+
/// [Simulation.dx], and the parameters used to construct the [Simulation],
384+
/// independent of the time.
385+
// TODO(gnprice): Some scroll physics in the framework violate that invariant; fix them.
386+
// An audit found three cases violating the invariant:
387+
// https://github.com/flutter/flutter/issues/120338
388+
// https://github.com/flutter/flutter/issues/120340
389+
// https://github.com/flutter/flutter/issues/109675
368390
Simulation? createBallisticSimulation(ScrollMetrics position, double velocity) {
369391
if (parent == null) {
370392
return null;

0 commit comments

Comments
 (0)