Unverified Commit 09ad9f3c authored by Greg Price's avatar Greg Price Committed by GitHub

Document ScrollPhysics invariant requiring ballistic motion (#120400)

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.
parent e00241a0
...@@ -365,6 +365,28 @@ class ScrollPhysics { ...@@ -365,6 +365,28 @@ class ScrollPhysics {
/// The given `position` is only valid during this method call. Do not keep a /// 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 /// reference to it to use later, as the values may update, may not update, or
/// may update to reflect an entirely unrelated scrollable. /// 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) { Simulation? createBallisticSimulation(ScrollMetrics position, double velocity) {
if (parent == null) { if (parent == null) {
return null; return null;
......
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