Commit 95fc9810 authored by Adam Barth's avatar Adam Barth

Improve tolerance for ending scroll animations

We had the units wrong on the tolerances. Previously we multiplied by the
device pixel ratio, which meant we got larger tolerances as we got more
resolution. Also, simplify logic in Newton for applying the tolerances.

Fixes #828
parent 11da9b02
...@@ -10,6 +10,12 @@ import 'package:newton/newton.dart'; ...@@ -10,6 +10,12 @@ import 'package:newton/newton.dart';
const double _kSecondsPerMillisecond = 1000.0; const double _kSecondsPerMillisecond = 1000.0;
const double _kScrollDrag = 0.025; const double _kScrollDrag = 0.025;
// TODO(abarth): These values won't work well if there's a scale transform.
final Tolerance _kDefaultScrollTolerance = new Tolerance(
velocity: 1.0 / (0.050 * ui.window.devicePixelRatio), // logical pixels per second
distance: 1.0 / ui.window.devicePixelRatio // logical pixels
);
/// An interface for controlling the behavior of scrollable widgets /// An interface for controlling the behavior of scrollable widgets
abstract class ScrollBehavior { abstract class ScrollBehavior {
/// Called when a drag gesture ends. Returns a simulation that /// Called when a drag gesture ends. Returns a simulation that
...@@ -102,29 +108,19 @@ class UnboundedBehavior extends ExtentScrollBehavior { ...@@ -102,29 +108,19 @@ class UnboundedBehavior extends ExtentScrollBehavior {
} }
} }
Simulation _createFlingScrollSimulation(double position, double velocity, double minScrollOffset, double maxScrollOffset) { Simulation _createFlingScrollSimulation(double position, double velocity, double minScrollOffset, double maxScrollOffset, Tolerance tolerance) {
double startVelocity = velocity * _kSecondsPerMillisecond; double startVelocity = velocity * _kSecondsPerMillisecond;
// Assume that we're rendering at atleast 15 FPS. Stop when we're
// scrolling less than one logical pixel per frame. We're essentially
// normalizing by the devicePixelRatio so that the threshold has the
// same effect independent of the device's pixel density.
double endVelocity = 15.0 * ui.window.devicePixelRatio;
// Similar to endVelocity. Stop scrolling when we're this close to
// destiniation scroll offset.
double endDistance = 0.5 * ui.window.devicePixelRatio;
SpringDescription spring = new SpringDescription.withDampingRatio(mass: 1.0, springConstant: 170.0, ratio: 1.1); SpringDescription spring = new SpringDescription.withDampingRatio(mass: 1.0, springConstant: 170.0, ratio: 1.1);
ScrollSimulation simulation = ScrollSimulation simulation =
new ScrollSimulation(position, startVelocity, minScrollOffset, maxScrollOffset, spring, _kScrollDrag) new ScrollSimulation(position, startVelocity, minScrollOffset, maxScrollOffset, spring, _kScrollDrag)
..tolerance = new Tolerance(velocity: endVelocity.abs(), distance: endDistance); ..tolerance = tolerance ?? _kDefaultScrollTolerance;
return simulation; return simulation;
} }
Simulation _createSnapScrollSimulation(double startOffset, double endOffset, double velocity) { Simulation _createSnapScrollSimulation(double startOffset, double endOffset, double velocity) {
double startVelocity = velocity * _kSecondsPerMillisecond; double startVelocity = velocity * _kSecondsPerMillisecond;
double endVelocity = 15.0 * ui.window.devicePixelRatio * velocity.sign; double endVelocity = velocity.sign * _kDefaultScrollTolerance.velocity;
return new FrictionSimulation.through(startOffset, endOffset, startVelocity, endVelocity); return new FrictionSimulation.through(startOffset, endOffset, startVelocity, endVelocity);
} }
...@@ -133,8 +129,8 @@ class OverscrollBehavior extends BoundedBehavior { ...@@ -133,8 +129,8 @@ class OverscrollBehavior extends BoundedBehavior {
OverscrollBehavior({ double contentExtent: 0.0, double containerExtent: 0.0 }) OverscrollBehavior({ double contentExtent: 0.0, double containerExtent: 0.0 })
: super(contentExtent: contentExtent, containerExtent: containerExtent); : super(contentExtent: contentExtent, containerExtent: containerExtent);
Simulation createFlingScrollSimulation(double position, double velocity) { Simulation createFlingScrollSimulation(double position, double velocity, { Tolerance tolerance }) {
return _createFlingScrollSimulation(position, velocity, minScrollOffset, maxScrollOffset); return _createFlingScrollSimulation(position, velocity, minScrollOffset, maxScrollOffset, tolerance);
} }
Simulation createSnapScrollSimulation(double startOffset, double endOffset, double velocity) { Simulation createSnapScrollSimulation(double startOffset, double endOffset, double velocity) {
...@@ -162,9 +158,9 @@ class OverscrollBehavior extends BoundedBehavior { ...@@ -162,9 +158,9 @@ class OverscrollBehavior extends BoundedBehavior {
class OverscrollWhenScrollableBehavior extends OverscrollBehavior { class OverscrollWhenScrollableBehavior extends OverscrollBehavior {
bool get isScrollable => contentExtent > containerExtent; bool get isScrollable => contentExtent > containerExtent;
Simulation createFlingScrollSimulation(double position, double velocity) { Simulation createFlingScrollSimulation(double position, double velocity, { Tolerance tolerance }) {
if (isScrollable || position < minScrollOffset || position > maxScrollOffset) if (isScrollable || position < minScrollOffset || position > maxScrollOffset)
return super.createFlingScrollSimulation(position, velocity); return super.createFlingScrollSimulation(position, velocity, tolerance: tolerance);
return null; return null;
} }
......
...@@ -57,10 +57,10 @@ class SpringSimulation extends Simulation { ...@@ -57,10 +57,10 @@ class SpringSimulation extends Simulation {
double dx(double time) => _solution.dx(time); double dx(double time) => _solution.dx(time);
@override bool isDone(double time) {
bool isDone(double time) => return _nearZero(_solution.x(time), tolerance.distance) &&
_nearEqual(x(time), _endPosition, this.tolerance.distance) && _nearZero(_solution.dx(time), tolerance.velocity);
_nearZero(dx(time), this.tolerance.velocity); }
} }
/// A SpringSimulation where the value of x() is guaranteed to have exactly the /// A SpringSimulation where the value of x() is guaranteed to have exactly the
...@@ -69,16 +69,5 @@ class ScrollSpringSimulation extends SpringSimulation { ...@@ -69,16 +69,5 @@ class ScrollSpringSimulation extends SpringSimulation {
ScrollSpringSimulation(SpringDescription desc, double start, double end, double velocity) ScrollSpringSimulation(SpringDescription desc, double start, double end, double velocity)
: super(desc, start, end, velocity); : super(desc, start, end, velocity);
bool _isDone(double position, double velocity) { double x(double time) => isDone(time) ? _endPosition : super.x(time);
return _nearEqual(position, _endPosition, tolerance.distance) && _nearZero(velocity, tolerance.velocity);
}
@override
double x(double time) {
double xAtTime = super.x(time);
return _isDone(xAtTime, dx(time)) ? _endPosition : xAtTime;
}
@override
bool isDone(double time) => _isDone(x(time), dx(time));
} }
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