diff --git a/packages/flutter/lib/src/animation/animation_performance.dart b/packages/flutter/lib/src/animation/animation_performance.dart index 9105498dc4..8111754442 100644 --- a/packages/flutter/lib/src/animation/animation_performance.dart +++ b/packages/flutter/lib/src/animation/animation_performance.dart @@ -85,7 +85,7 @@ class AnimationPerformance implements WatchableAnimationPerformance { /// The progress of this performance along the timeline /// /// Note: Setting this value stops the current animation. - double get progress => _timeline.value; + double get progress => _timeline.value.clamp(0.0, 1.0); void set progress(double t) { // TODO(mpcomplete): should this affect |direction|? stop(); diff --git a/packages/flutter/lib/src/animation/timeline.dart b/packages/flutter/lib/src/animation/timeline.dart index 75da47d5f8..29005c75f5 100644 --- a/packages/flutter/lib/src/animation/timeline.dart +++ b/packages/flutter/lib/src/animation/timeline.dart @@ -5,30 +5,28 @@ import 'dart:async'; import 'package:newton/newton.dart'; - +import 'package:sky/src/animation/curves.dart'; +import 'package:sky/src/animation/animated_value.dart'; import 'package:sky/src/animation/animated_simulation.dart'; /// A simulation that linearly varies from [begin] to [end] over [duration] -class TweenSimulation extends Simulation { +class _TweenSimulation extends Simulation { final double _durationInSeconds; + final AnimatedValue _tween; - /// The initial value of the simulation - final double begin; - - /// The terminal value of the simulation - final double end; - - TweenSimulation(Duration duration, this.begin, this.end) : - _durationInSeconds = duration.inMicroseconds / Duration.MICROSECONDS_PER_SECOND { + _TweenSimulation(double begin, double end, Duration duration, Curve curve) + : _durationInSeconds = duration.inMicroseconds / Duration.MICROSECONDS_PER_SECOND, + _tween = new AnimatedValue(begin, end: end, curve: curve) { assert(_durationInSeconds > 0.0); - assert(begin != null && begin >= 0.0 && begin <= 1.0); - assert(end != null && end >= 0.0 && end <= 1.0); + assert(begin != null); + assert(end != null); } double x(double timeInSeconds) { assert(timeInSeconds >= 0.0); - final double t = timeInSeconds / _durationInSeconds; - return t >= 1.0 ? end : begin + (end - begin) * t; + final double t = (timeInSeconds / _durationInSeconds).clamp(0.0, 1.0); + _tween.setProgress(t, Direction.forward); + return _tween.value; } double dx(double timeInSeconds) => 1.0; @@ -45,9 +43,9 @@ class Timeline { AnimatedSimulation _animation; /// The current value of the timeline - double get value => _animation.value.clamp(0.0, 1.0); + double get value => _animation.value; void set value(double newValue) { - assert(newValue != null && newValue >= 0.0 && newValue <= 1.0); + assert(newValue != null); assert(!isAnimating); _animation.value = newValue; } @@ -55,23 +53,14 @@ class Timeline { /// Whether the timeline is currently animating bool get isAnimating => _animation.isAnimating; - Future _start({ - Duration duration, - double begin: 0.0, - double end: 1.0 - }) { - assert(!_animation.isAnimating); - assert(duration > Duration.ZERO); - return _animation.start(new TweenSimulation(duration, begin, end)); - } - /// Animate value of the timeline to the given target over the given duration /// /// Returns a future that resolves when the timeline stops animating, /// typically when the timeline arives at the target value. - Future animateTo(double target, { Duration duration }) { + Future animateTo(double target, { Duration duration, Curve curve: linear }) { assert(duration > Duration.ZERO); - return _start(duration: duration, begin: value, end: target); + assert(!_animation.isAnimating); + return _animation.start(new _TweenSimulation(value, target, duration, curve)); } /// Stop animating the timeline @@ -79,7 +68,7 @@ class Timeline { _animation.stop(); } - // Gives the given simulation control over the timeline + /// Gives the given simulation control over the timeline Future fling(Simulation simulation) { stop(); return _animation.start(simulation); diff --git a/packages/flutter/lib/src/widgets/scrollable.dart b/packages/flutter/lib/src/widgets/scrollable.dart index f5ac199d25..e09fe4f861 100644 --- a/packages/flutter/lib/src/widgets/scrollable.dart +++ b/packages/flutter/lib/src/widgets/scrollable.dart @@ -51,16 +51,10 @@ abstract class ScrollableState extends State { super.initState(); if (config.initialScrollOffset is double) _scrollOffset = config.initialScrollOffset; - _toEndAnimation = new AnimatedSimulation(_setScrollOffset); - _toOffsetAnimation = new ValueAnimation() - ..addListener(() { - AnimatedValue offset = _toOffsetAnimation.variable; - _setScrollOffset(offset.value); - }); + _animation = new Timeline(_setScrollOffset); } - AnimatedSimulation _toEndAnimation; // See _startToEndAnimation() - ValueAnimation _toOffsetAnimation; // Started by scrollTo() + Timeline _animation; double _scrollOffset = 0.0; double get scrollOffset => _scrollOffset; @@ -106,23 +100,10 @@ abstract class ScrollableState extends State { Widget buildContent(BuildContext context); - Future _startToOffsetAnimation(double newScrollOffset, Duration duration, Curve curve) { - _stopAnimations(); - _toOffsetAnimation - ..variable = new AnimatedValue(scrollOffset, - end: newScrollOffset, - curve: curve - ) - ..progress = 0.0 - ..duration = duration; - return _toOffsetAnimation.play(); - } - - void _stopAnimations() { - if (_toOffsetAnimation.isAnimating) - _toOffsetAnimation.stop(); - if (_toEndAnimation.isAnimating) - _toEndAnimation.stop(); + Future _animateTo(double newScrollOffset, Duration duration, Curve curve) { + _animation.stop(); + _animation.value = scrollOffset; + return _animation.animateTo(newScrollOffset, duration: duration, curve: curve); } bool _scrollOffsetIsInBounds(double offset) { @@ -165,16 +146,16 @@ abstract class ScrollableState extends State { } Future _startToEndAnimation({ double velocity }) { - _stopAnimations(); + _animation.stop(); Simulation simulation = _createSnapSimulation(velocity) ?? _createFlingSimulation(velocity ?? 0.0); if (simulation == null) return new Future.value(); - return _toEndAnimation.start(simulation); + return _animation.fling(simulation); } void dispose() { - _stopAnimations(); + _animation.stop(); super.dispose(); } @@ -193,12 +174,12 @@ abstract class ScrollableState extends State { return new Future.value(); if (duration == null) { - _stopAnimations(); + _animation.stop(); _setScrollOffset(newScrollOffset); return new Future.value(); } - return _startToOffsetAnimation(newScrollOffset, duration, curve); + return _animateTo(newScrollOffset, duration, curve); } Future scrollBy(double scrollDelta, { Duration duration, Curve curve }) { @@ -209,7 +190,7 @@ abstract class ScrollableState extends State { Future fling(Offset velocity) { if (velocity != Offset.zero) return _startToEndAnimation(velocity: _scrollVelocity(velocity)); - if (!_toEndAnimation.isAnimating && (_toOffsetAnimation == null || !_toOffsetAnimation.isAnimating)) + if (!_animation.isAnimating) return settleScrollOffset(); return new Future.value(); } @@ -226,7 +207,7 @@ abstract class ScrollableState extends State { } void _handlePointerDown(_) { - _stopAnimations(); + _animation.stop(); } void _handleDragUpdate(double delta) {