From d3dbc7214526f2d9b105b1d15c5fcf95cd05c98b Mon Sep 17 00:00:00 2001 From: Matt Perry Date: Mon, 3 Aug 2015 16:56:36 -0400 Subject: [PATCH] Use transitions for Dismissable. Simplifies the code a bit. --- .../lib/animation/animation_performance.dart | 6 +- sky/packages/sky/lib/widgets/dismissable.dart | 118 ++++++++---------- sky/packages/sky/lib/widgets/transitions.dart | 41 ++++++ 3 files changed, 96 insertions(+), 69 deletions(-) diff --git a/sky/packages/sky/lib/animation/animation_performance.dart b/sky/packages/sky/lib/animation/animation_performance.dart index 7c2e562677..d1a556fbc8 100644 --- a/sky/packages/sky/lib/animation/animation_performance.dart +++ b/sky/packages/sky/lib/animation/animation_performance.dart @@ -137,11 +137,11 @@ class AnimationPerformance { } Future _animateTo(double target) { - double remainingDistance = (target - timeline.value).abs(); + Duration remainingDuration = duration * (target - timeline.value).abs(); timeline.stop(); - if (remainingDistance == 0.0) + if (remainingDuration == Duration.ZERO) return new Future.value(); - return timeline.animateTo(target, duration: duration * remainingDistance); + return timeline.animateTo(target, duration: remainingDuration); } void _tick(double t) { diff --git a/sky/packages/sky/lib/widgets/dismissable.dart b/sky/packages/sky/lib/widgets/dismissable.dart index 6c078b8781..9b030a69a0 100644 --- a/sky/packages/sky/lib/widgets/dismissable.dart +++ b/sky/packages/sky/lib/widgets/dismissable.dart @@ -7,14 +7,14 @@ import 'dart:sky' as sky; import 'package:sky/animation/animated_value.dart'; import 'package:sky/animation/animation_performance.dart'; import 'package:sky/animation/curves.dart'; -import 'package:sky/widgets/animated_component.dart'; import 'package:sky/widgets/basic.dart'; +import 'package:sky/widgets/transitions.dart'; import 'package:sky/widgets/widget.dart'; import 'package:vector_math/vector_math.dart'; const Duration _kCardDismissFadeout = const Duration(milliseconds: 200); const Duration _kCardDismissResize = const Duration(milliseconds: 300); -const double _kCardDismissResizeDelay = 0.4; +final Interval _kCardDismissResizeInterval = new Interval(0.4, 1.0); const double _kMinFlingVelocity = 700.0; const double _kMinFlingVelocityDelta = 400.0; const double _kFlingVelocityScale = 1.0 / 300.0; @@ -23,7 +23,7 @@ const double _kDismissCardThreshold = 0.6; typedef void ResizedCallback(); typedef void DismissedCallback(); -class Dismissable extends AnimatedComponent { +class Dismissable extends StatefulComponent { Dismissable({ Key key, @@ -37,8 +37,6 @@ class Dismissable extends AnimatedComponent { ResizedCallback onResized; DismissedCallback onDismissed; - AnimatedValue _position; - AnimatedValue _opacity; AnimationPerformance _fadePerformance; AnimationPerformance _resizePerformance; @@ -47,29 +45,23 @@ class Dismissable extends AnimatedComponent { bool _dragUnderway = false; void initState() { - _position = new AnimatedValue(Point.origin); - _opacity = new AnimatedValue(1.0, end: 0.0); - _fadePerformance = new AnimationPerformance() - ..duration = _kCardDismissFadeout - ..variable = new AnimatedList([_position, _opacity]) - ..addListener(_handleFadeProgressChanged); + _fadePerformance = new AnimationPerformance(duration: _kCardDismissFadeout); } - void _handleFadeProgressChanged() { - setState(() { - if (_fadePerformance.isCompleted && !_dragUnderway) - _startResizePerformance(); - }); + void _handleFadeCompleted() { + if (!_dragUnderway) + _startResizePerformance(); } void syncFields(Dismissable source) { child = source.child; onResized = source.onResized; onDismissed = source.onDismissed; - super.syncFields(source); } Point get _activeCardDragEndPoint { + if (!_isActive) + return Point.origin; assert(_size != null); return new Point(_dragX.sign * _size.width * _kDismissCardThreshold, 0.0); } @@ -91,38 +83,27 @@ class Dismissable extends AnimatedComponent { void _startResizePerformance() { assert(_size != null); assert(_fadePerformance != null); + assert(_fadePerformance.isCompleted); assert(_resizePerformance == null); - // TODO(hansmuller): _fadePerformance is completed; stop shouldn't be needed. - _fadePerformance.stop(); - - AnimatedValue dismissHeight = new AnimatedValue(_size.height, - end: 0.0, - curve: ease, - interval: new Interval(_kCardDismissResizeDelay, 1.0) - ); - _resizePerformance = new AnimationPerformance() - ..variable = dismissHeight - ..duration = _kCardDismissResize - ..addListener(_handleResizeProgressChanged) - ..play(); + setState(() { + _resizePerformance = new AnimationPerformance() + ..duration = _kCardDismissResize + ..addListener(_handleResizeProgressChanged); + }); } void _handleResizeProgressChanged() { - setState(() { - if (_resizePerformance.isCompleted) - _maybeCallOnDismissed(); - else - _maybeCallOnResized(); - }); + if (_resizePerformance.isCompleted) + _maybeCallOnDismissed(); + else + _maybeCallOnResized(); } void _handlePointerDown(sky.PointerEvent event) { - setState(() { - _dragUnderway = true; - _dragX = 0.0; - _fadePerformance.progress = 0.0; - }); + _dragUnderway = true; + _dragX = 0.0; + _fadePerformance.progress = 0.0; } void _handlePointerMove(sky.PointerEvent event) { @@ -131,26 +112,21 @@ class Dismissable extends AnimatedComponent { double oldDragX = _dragX; _dragX += event.dx; - setState(() { - if (!_fadePerformance.isAnimating) { - if (oldDragX.sign != _dragX.sign) - _position.end = _activeCardDragEndPoint; - _fadePerformance.progress = _dragX.abs() / (_size.width * _kDismissCardThreshold); - } - }); + if (oldDragX.sign != _dragX.sign) + setState(() {}); // Rebuild to update the new drag endpoint. + if (!_fadePerformance.isAnimating) + _fadePerformance.progress = _dragX.abs() / (_size.width * _kDismissCardThreshold); } void _handlePointerUpOrCancel(_) { if (!_isActive) return; - setState(() { - _dragUnderway = false; - if (_fadePerformance.isCompleted) - _startResizePerformance(); - else if (!_fadePerformance.isAnimating) - _fadePerformance.reverse(); - }); + _dragUnderway = false; + if (_fadePerformance.isCompleted) + _startResizePerformance(); + else if (!_fadePerformance.isAnimating) + _fadePerformance.reverse(); } bool _isHorizontalFlingGesture(sky.GestureEvent event) { @@ -166,24 +142,31 @@ class Dismissable extends AnimatedComponent { if (_isHorizontalFlingGesture(event)) { _dragUnderway = false; _dragX = event.velocityX.sign; - _position.end = _activeCardDragEndPoint; _fadePerformance.fling(Direction.forward, velocity: event.velocityX.abs() * _kFlingVelocityScale); } } void _handleSizeChanged(Size newSize) { - _size = new Size.copy(newSize); - _position.end = _activeCardDragEndPoint; + setState(() { + _size = new Size.copy(newSize); + }); } Widget build() { if (_resizePerformance != null) { - AnimatedValue height = _resizePerformance.variable; - return new Container(height: height.value); + AnimatedValue dismissHeight = new AnimatedValue( + _size.height, + end: 0.0, + curve: ease, + interval: _kCardDismissResizeInterval + ); + + return new SquashTransition( + performance: _resizePerformance, + direction: Direction.forward, + height: dismissHeight); } - Matrix4 transform = new Matrix4.identity(); - transform.translate(_position.value.x, _position.value.y); return new Listener( onPointerDown: _handlePointerDown, onPointerMove: _handlePointerMove, @@ -192,10 +175,13 @@ class Dismissable extends AnimatedComponent { onGestureFlingStart: _handleFlingStart, child: new SizeObserver( callback: _handleSizeChanged, - child: new Opacity( - opacity: _opacity.value, - child: new Transform( - transform: transform, + child: new SlideIn( + performance: _fadePerformance, + position: new AnimatedValue(Point.origin, end: _activeCardDragEndPoint), + child: new FadeIn( + performance: _fadePerformance, + onCompleted: _handleFadeCompleted, + opacity: new AnimatedValue(1.0, end: 0.0), child: child ) ) diff --git a/sky/packages/sky/lib/widgets/transitions.dart b/sky/packages/sky/lib/widgets/transitions.dart index fdb9e085f8..2c1a4c3d30 100644 --- a/sky/packages/sky/lib/widgets/transitions.dart +++ b/sky/packages/sky/lib/widgets/transitions.dart @@ -8,6 +8,8 @@ import 'package:sky/animation/animated_value.dart'; import 'package:sky/widgets/basic.dart'; import 'package:vector_math/vector_math.dart'; +dynamic _maybe(AnimatedValue x) => x != null ? x.value : null; + abstract class TransitionBase extends AnimatedComponent { TransitionBase({ Key key, @@ -68,6 +70,7 @@ abstract class TransitionBase extends AnimatedComponent { Widget build(); } +// TODO(mpcomplete): rename SlideTransition class SlideIn extends TransitionBase { // TODO(mpcomplete): this constructor is mostly boilerplate, passing values // to super. Is there a simpler way? @@ -103,6 +106,7 @@ class SlideIn extends TransitionBase { } } +// TODO(mpcomplete): rename FadeTransition class FadeIn extends TransitionBase { FadeIn({ Key key, @@ -167,3 +171,40 @@ class ColorTransition extends TransitionBase { ); } } + +class SquashTransition extends TransitionBase { + SquashTransition({ + Key key, + this.width, + this.height, + Duration duration, + AnimationPerformance performance, + Direction direction, + Function onDismissed, + Function onCompleted, + Widget child + }) : super(key: key, + duration: duration, + performance: performance, + direction: direction, + onDismissed: onDismissed, + onCompleted: onCompleted, + child: child); + + AnimatedValue width; + AnimatedValue height; + + void syncFields(SquashTransition updated) { + width = updated.width; + height = updated.height; + super.syncFields(updated); + } + + Widget build() { + if (width != null) + width.setProgress(performance.progress); + if (height != null) + height.setProgress(performance.progress); + return new SizedBox(width: _maybe(width), height: _maybe(height), child: child); + } +} -- GitLab