Commit b9f4e5da authored by Adam Barth's avatar Adam Barth Committed by GitHub

Make AnimatedCrossFade's alignment configurable (#9973)

The default is topCenter, which is sensible, but someone might want to use a
bottomCenter alignment, for example.
parent 7160ecfb
...@@ -297,7 +297,7 @@ class RenderStack extends RenderBox ...@@ -297,7 +297,7 @@ class RenderStack extends RenderBox
/// top left corners. /// top left corners.
RenderStack({ RenderStack({
List<RenderBox> children, List<RenderBox> children,
FractionalOffset alignment: FractionalOffset.center, FractionalOffset alignment: FractionalOffset.topLeft,
StackFit fit: StackFit.loose, StackFit fit: StackFit.loose,
Overflow overflow: Overflow.clip Overflow overflow: Overflow.clip
}) : _alignment = alignment, }) : _alignment = alignment,
......
...@@ -51,6 +51,7 @@ class AnimatedCrossFade extends StatefulWidget { ...@@ -51,6 +51,7 @@ class AnimatedCrossFade extends StatefulWidget {
this.firstCurve: Curves.linear, this.firstCurve: Curves.linear,
this.secondCurve: Curves.linear, this.secondCurve: Curves.linear,
this.sizeCurve: Curves.linear, this.sizeCurve: Curves.linear,
this.alignment: FractionalOffset.topCenter,
@required this.crossFadeState, @required this.crossFadeState,
@required this.duration @required this.duration
}) : assert(firstCurve != null), }) : assert(firstCurve != null),
...@@ -77,14 +78,25 @@ class AnimatedCrossFade extends StatefulWidget { ...@@ -77,14 +78,25 @@ class AnimatedCrossFade extends StatefulWidget {
final Duration duration; final Duration duration;
/// The fade curve of the first child. /// The fade curve of the first child.
///
/// Defaults to [Curves.linear].
final Curve firstCurve; final Curve firstCurve;
/// The fade curve of the second child. /// The fade curve of the second child.
///
/// Defaults to [Curves.linear].
final Curve secondCurve; final Curve secondCurve;
/// The curve of the animation between the two children's sizes. /// The curve of the animation between the two children's sizes.
///
/// Defaults to [Curves.linear].
final Curve sizeCurve; final Curve sizeCurve;
/// How the children should be aligned while the size is animating.
///
/// Defaults to [FractionalOffset.topCenter].
final FractionalOffset alignment;
@override @override
_AnimatedCrossFadeState createState() => new _AnimatedCrossFadeState(); _AnimatedCrossFadeState createState() => new _AnimatedCrossFadeState();
} }
...@@ -152,7 +164,7 @@ class _AnimatedCrossFadeState extends State<AnimatedCrossFade> with TickerProvid ...@@ -152,7 +164,7 @@ class _AnimatedCrossFadeState extends State<AnimatedCrossFade> with TickerProvid
children = <Widget>[ children = <Widget>[
new FadeTransition( new FadeTransition(
opacity: _secondAnimation, opacity: _secondAnimation,
child: widget.secondChild child: widget.secondChild,
), ),
new Positioned( new Positioned(
// TODO(dragostis): Add a way to crop from top right for // TODO(dragostis): Add a way to crop from top right for
...@@ -162,15 +174,15 @@ class _AnimatedCrossFadeState extends State<AnimatedCrossFade> with TickerProvid ...@@ -162,15 +174,15 @@ class _AnimatedCrossFadeState extends State<AnimatedCrossFade> with TickerProvid
right: 0.0, right: 0.0,
child: new FadeTransition( child: new FadeTransition(
opacity: _firstAnimation, opacity: _firstAnimation,
child: widget.firstChild child: widget.firstChild,
) ),
) ),
]; ];
} else { } else {
children = <Widget>[ children = <Widget>[
new FadeTransition( new FadeTransition(
opacity: _firstAnimation, opacity: _firstAnimation,
child: widget.firstChild child: widget.firstChild,
), ),
new Positioned( new Positioned(
// TODO(dragostis): Add a way to crop from top right for // TODO(dragostis): Add a way to crop from top right for
...@@ -180,24 +192,24 @@ class _AnimatedCrossFadeState extends State<AnimatedCrossFade> with TickerProvid ...@@ -180,24 +192,24 @@ class _AnimatedCrossFadeState extends State<AnimatedCrossFade> with TickerProvid
right: 0.0, right: 0.0,
child: new FadeTransition( child: new FadeTransition(
opacity: _secondAnimation, opacity: _secondAnimation,
child: widget.secondChild child: widget.secondChild,
) ),
) ),
]; ];
} }
return new ClipRect( return new ClipRect(
child: new AnimatedSize( child: new AnimatedSize(
key: new ValueKey<Key>(widget.key), key: new ValueKey<Key>(widget.key),
alignment: FractionalOffset.topCenter, alignment: widget.alignment,
duration: widget.duration, duration: widget.duration,
curve: widget.sizeCurve, curve: widget.sizeCurve,
vsync: this, vsync: this,
child: new Stack( child: new Stack(
overflow: Overflow.visible, overflow: Overflow.visible,
children: children children: children,
) ),
) ),
); );
} }
} }
...@@ -78,4 +78,57 @@ void main() { ...@@ -78,4 +78,57 @@ void main() {
expect(box.size.width, equals(200.0)); expect(box.size.width, equals(200.0));
expect(box.size.height, 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));
});
} }
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