Skip to content

Commit

Permalink
Document ScrollPhysics invariant requiring ballistic motion (#120400)
Browse files Browse the repository at this point in the history
Fixes #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: #120340 macOS touchpad flinging, and #109675 never.

The third is #120338, affecting default scrolling on Android and
other non-Apple platforms.  I'll send a PR to fix that shortly,
and another for #109675.

As discussed at #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.
  • Loading branch information
gnprice authored Feb 16, 2023
1 parent e00241a commit 09ad9f3
Showing 1 changed file with 22 additions and 0 deletions.
22 changes: 22 additions & 0 deletions packages/flutter/lib/src/widgets/scroll_physics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,28 @@ class ScrollPhysics {
/// The given `position` is only valid during this method call. Do not keep a
/// reference to it to use later, as the values may update, may not update, or
/// may update to reflect an entirely unrelated scrollable.
///
/// This method can potentially be called in every frame, even in the middle
/// of what the user perceives as a single ballistic scroll. For example, in
/// a [ListView] when previously off-screen items come into view and are laid
/// out, this method may be called with a new [ScrollMetrics.maxScrollExtent].
/// The method implementation should ensure that when the same ballistic
/// scroll motion is still intended, these calls have no side effects on the
/// physics beyond continuing that motion.
///
/// Generally this is ensured by having the [Simulation] conform to a physical
/// metaphor of a particle in ballistic flight, where the forces on the
/// particle depend only on its position, velocity, and environment, and not
/// on the current time or any internal state. This means that the
/// time-derivative of [Simulation.dx] should be possible to write
/// mathematically as a function purely of the values of [Simulation.x],
/// [Simulation.dx], and the parameters used to construct the [Simulation],
/// independent of the time.
// TODO(gnprice): Some scroll physics in the framework violate that invariant; fix them.
// An audit found three cases violating the invariant:
// https://github.com/flutter/flutter/issues/120338
// https://github.com/flutter/flutter/issues/120340
// https://github.com/flutter/flutter/issues/109675
Simulation? createBallisticSimulation(ScrollMetrics position, double velocity) {
if (parent == null) {
return null;
Expand Down

0 comments on commit 09ad9f3

Please sign in to comment.