diff --git a/packages/flutter/lib/src/animation/animations.dart b/packages/flutter/lib/src/animation/animations.dart index 62490a662c..03d30f530a 100644 --- a/packages/flutter/lib/src/animation/animations.dart +++ b/packages/flutter/lib/src/animation/animations.dart @@ -281,13 +281,13 @@ class ReverseAnimation extends Animation double get value => 1.0 - parent.value; AnimationStatus _reverseStatus(AnimationStatus status) { + assert(status != null); switch (status) { case AnimationStatus.forward: return AnimationStatus.reverse; case AnimationStatus.reverse: return AnimationStatus.forward; case AnimationStatus.completed: return AnimationStatus.dismissed; case AnimationStatus.dismissed: return AnimationStatus.completed; } - assert(status != null); return null; } @@ -399,7 +399,7 @@ class CurvedAnimation extends Animation with AnimationWithParentMixin } _currentTrain.addStatusListener(_statusChangeHandler); _currentTrain.addListener(_valueChangeHandler); - if (_nextTrain != null) - _nextTrain.addListener(_valueChangeHandler); + _nextTrain?.addListener(_valueChangeHandler); assert(_mode != null); } @@ -479,14 +478,13 @@ class TrainHoppingAnimation extends Animation break; } if (hop) { - _currentTrain.removeStatusListener(_statusChangeHandler); - _currentTrain.removeListener(_valueChangeHandler); + _currentTrain + ..removeStatusListener(_statusChangeHandler) + ..removeListener(_valueChangeHandler); _currentTrain = _nextTrain; - // TODO(hixie): This should be setting a status listener on the next - // train, not a value listener, and it should pass in _statusChangeHandler, - // not _valueChangeHandler - _nextTrain.addListener(_valueChangeHandler); - _statusChangeHandler(_nextTrain.status); + _nextTrain = null; + _currentTrain.addStatusListener(_statusChangeHandler); + _statusChangeHandler(_currentTrain.status); } } double newValue = value; @@ -510,10 +508,8 @@ class TrainHoppingAnimation extends Animation _currentTrain.removeStatusListener(_statusChangeHandler); _currentTrain.removeListener(_valueChangeHandler); _currentTrain = null; - if (_nextTrain != null) { - _nextTrain.removeListener(_valueChangeHandler); - _nextTrain = null; - } + _nextTrain?.removeListener(_valueChangeHandler); + _nextTrain = null; } @override diff --git a/packages/flutter/test/animation/animations_test.dart b/packages/flutter/test/animation/animations_test.dart index 55a414e429..6217fd8b3a 100644 --- a/packages/flutter/test/animation/animations_test.dart +++ b/packages/flutter/test/animation/animations_test.dart @@ -15,9 +15,30 @@ void main() { test('toString control test', () { expect(kAlwaysCompleteAnimation.toString(), isOneLineDescription); expect(kAlwaysDismissedAnimation.toString(), isOneLineDescription); + expect(new AlwaysStoppedAnimation(0.5).toString(), isOneLineDescription); + CurvedAnimation curvedAnimation = new CurvedAnimation( + parent: kAlwaysDismissedAnimation, + curve: Curves.ease + ); + expect(curvedAnimation.toString(), isOneLineDescription); + curvedAnimation.reverseCurve = Curves.elasticOut; + expect(curvedAnimation.toString(), isOneLineDescription); + AnimationController controller = new AnimationController( + duration: const Duration(milliseconds: 500) + ); + controller + ..value = 0.5 + ..reverse(); + curvedAnimation = new CurvedAnimation( + parent: controller, + curve: Curves.ease, + reverseCurve: Curves.elasticOut + ); + expect(curvedAnimation.toString(), isOneLineDescription); + controller.stop(); }); - test('toString control test', () { + test('ProxyAnimation.toString control test', () { ProxyAnimation animation = new ProxyAnimation(); expect(animation.value, 0.0); expect(animation.status, AnimationStatus.dismissed); @@ -25,4 +46,61 @@ void main() { animation.parent = kAlwaysDismissedAnimation; expect(animation.toString(), isOneLineDescription); }); + + test('ProxyAnimation set parent generates value changed', () { + AnimationController controller = new AnimationController(); + controller.value = 0.5; + bool didReceiveCallback = false; + ProxyAnimation animation = new ProxyAnimation() + ..addListener(() { + didReceiveCallback = true; + }); + expect(didReceiveCallback, isFalse); + animation.parent = controller; + expect(didReceiveCallback, isTrue); + didReceiveCallback = false; + expect(didReceiveCallback, isFalse); + controller.value = 0.6; + expect(didReceiveCallback, isTrue); + }); + + test('ReverseAnimation calls listeners', () { + AnimationController controller = new AnimationController(); + controller.value = 0.5; + bool didReceiveCallback = false; + void listener() { + didReceiveCallback = true; + } + ReverseAnimation animation = new ReverseAnimation(controller) + ..addListener(listener); + expect(didReceiveCallback, isFalse); + controller.value = 0.6; + expect(didReceiveCallback, isTrue); + didReceiveCallback = false; + animation.removeListener(listener); + expect(didReceiveCallback, isFalse); + controller.value = 0.7; + expect(didReceiveCallback, isFalse); + expect(animation.toString(), isOneLineDescription); + }); + + test('TrainHoppingAnimation', () { + AnimationController currentTrain = new AnimationController(); + AnimationController nextTrain = new AnimationController(); + currentTrain.value = 0.5; + nextTrain.value = 0.75; + bool didSwitchTrains = false; + TrainHoppingAnimation animation = new TrainHoppingAnimation( + currentTrain, nextTrain, onSwitchedTrain: () { + didSwitchTrains = true; + }); + expect(didSwitchTrains, isFalse); + expect(animation.value, 0.5); + expect(animation.toString(), isOneLineDescription); + nextTrain.value = 0.25; + expect(didSwitchTrains, isTrue); + expect(animation.value, 0.25); + expect(animation.toString(), isOneLineDescription); + expect(animation.toString(), contains('no next')); + }); }