diff --git a/packages/flutter/lib/src/rendering/stack.dart b/packages/flutter/lib/src/rendering/stack.dart index 97f93ea15a..eef07a5a41 100644 --- a/packages/flutter/lib/src/rendering/stack.dart +++ b/packages/flutter/lib/src/rendering/stack.dart @@ -297,7 +297,7 @@ class RenderStack extends RenderBox /// top left corners. RenderStack({ List children, - FractionalOffset alignment: FractionalOffset.center, + FractionalOffset alignment: FractionalOffset.topLeft, StackFit fit: StackFit.loose, Overflow overflow: Overflow.clip }) : _alignment = alignment, diff --git a/packages/flutter/lib/src/widgets/animated_cross_fade.dart b/packages/flutter/lib/src/widgets/animated_cross_fade.dart index 5ed81cf2ea..8c64b889a4 100644 --- a/packages/flutter/lib/src/widgets/animated_cross_fade.dart +++ b/packages/flutter/lib/src/widgets/animated_cross_fade.dart @@ -51,6 +51,7 @@ class AnimatedCrossFade extends StatefulWidget { this.firstCurve: Curves.linear, this.secondCurve: Curves.linear, this.sizeCurve: Curves.linear, + this.alignment: FractionalOffset.topCenter, @required this.crossFadeState, @required this.duration }) : assert(firstCurve != null), @@ -77,14 +78,25 @@ class AnimatedCrossFade extends StatefulWidget { final Duration duration; /// The fade curve of the first child. + /// + /// Defaults to [Curves.linear]. final Curve firstCurve; /// The fade curve of the second child. + /// + /// Defaults to [Curves.linear]. final Curve secondCurve; /// The curve of the animation between the two children's sizes. + /// + /// Defaults to [Curves.linear]. final Curve sizeCurve; + /// How the children should be aligned while the size is animating. + /// + /// Defaults to [FractionalOffset.topCenter]. + final FractionalOffset alignment; + @override _AnimatedCrossFadeState createState() => new _AnimatedCrossFadeState(); } @@ -152,7 +164,7 @@ class _AnimatedCrossFadeState extends State with TickerProvid children = [ new FadeTransition( opacity: _secondAnimation, - child: widget.secondChild + child: widget.secondChild, ), new Positioned( // TODO(dragostis): Add a way to crop from top right for @@ -162,15 +174,15 @@ class _AnimatedCrossFadeState extends State with TickerProvid right: 0.0, child: new FadeTransition( opacity: _firstAnimation, - child: widget.firstChild - ) - ) + child: widget.firstChild, + ), + ), ]; } else { children = [ new FadeTransition( opacity: _firstAnimation, - child: widget.firstChild + child: widget.firstChild, ), new Positioned( // TODO(dragostis): Add a way to crop from top right for @@ -180,24 +192,24 @@ class _AnimatedCrossFadeState extends State with TickerProvid right: 0.0, child: new FadeTransition( opacity: _secondAnimation, - child: widget.secondChild - ) - ) + child: widget.secondChild, + ), + ), ]; } return new ClipRect( child: new AnimatedSize( key: new ValueKey(widget.key), - alignment: FractionalOffset.topCenter, + alignment: widget.alignment, duration: widget.duration, curve: widget.sizeCurve, vsync: this, child: new Stack( overflow: Overflow.visible, - children: children - ) - ) + children: children, + ), + ), ); } } diff --git a/packages/flutter/test/widgets/animated_cross_fade_test.dart b/packages/flutter/test/widgets/animated_cross_fade_test.dart index 70ad32b13d..d0a9dfc434 100644 --- a/packages/flutter/test/widgets/animated_cross_fade_test.dart +++ b/packages/flutter/test/widgets/animated_cross_fade_test.dart @@ -78,4 +78,57 @@ void main() { expect(box.size.width, equals(200.0)); expect(box.size.height, equals(200.0)); }); + + testWidgets('AnimatedCrossFade alignment', (WidgetTester tester) async { + final Key firstKey = new UniqueKey(); + final Key secondKey = new UniqueKey(); + + await tester.pumpWidget( + new Center( + child: new AnimatedCrossFade( + alignment: FractionalOffset.bottomRight, + firstChild: new SizedBox( + key: firstKey, + width: 100.0, + height: 100.0 + ), + secondChild: new SizedBox( + key: secondKey, + width: 200.0, + height: 200.0 + ), + duration: const Duration(milliseconds: 200), + crossFadeState: CrossFadeState.showFirst + ) + ) + ); + + await tester.pumpWidget( + new Center( + child: new AnimatedCrossFade( + alignment: FractionalOffset.bottomRight, + firstChild: new SizedBox( + key: firstKey, + width: 100.0, + height: 100.0 + ), + secondChild: new SizedBox( + key: secondKey, + width: 200.0, + height: 200.0 + ), + duration: const Duration(milliseconds: 200), + crossFadeState: CrossFadeState.showSecond + ) + ) + ); + + await tester.pump(const Duration(milliseconds: 100)); + + final RenderBox box1 = tester.renderObject(find.byKey(firstKey)); + final RenderBox box2 = tester.renderObject(find.byKey(secondKey)); + expect(box1.localToGlobal(Offset.zero), const Offset(275.0, 175.0)); + expect(box2.localToGlobal(Offset.zero), const Offset(275.0, 175.0)); + }); + }