diff --git a/packages/flutter/lib/src/widgets/animated_container.dart b/packages/flutter/lib/src/widgets/animated_container.dart deleted file mode 100644 index 5c247f0b28..0000000000 --- a/packages/flutter/lib/src/widgets/animated_container.dart +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'package:flutter/animation.dart'; - -import 'basic.dart'; -import 'framework.dart'; - -import 'package:vector_math/vector_math_64.dart'; - -/// An animated value that interpolates [BoxConstraint]s. -class AnimatedBoxConstraintsValue extends AnimatedValue { - AnimatedBoxConstraintsValue(BoxConstraints begin, { BoxConstraints end, Curve curve, Curve reverseCurve }) - : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); - - BoxConstraints lerp(double t) => BoxConstraints.lerp(begin, end, t); -} - -/// An animated value that interpolates [Decoration]s. -class AnimatedDecorationValue extends AnimatedValue { - AnimatedDecorationValue(Decoration begin, { Decoration end, Curve curve, Curve reverseCurve }) - : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); - - Decoration lerp(double t) { - if (begin == null && end == null) - return null; - if (end == null) - return begin.lerpTo(end, t); - return end.lerpFrom(begin, t); - } -} - -/// An animated value that interpolates [EdgeDims]. -class AnimatedEdgeDimsValue extends AnimatedValue { - AnimatedEdgeDimsValue(EdgeDims begin, { EdgeDims end, Curve curve, Curve reverseCurve }) - : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); - - EdgeDims lerp(double t) => EdgeDims.lerp(begin, end, t); -} - -/// An animated value that interpolates [Matrix4]s. -/// -/// Currently this class works only for translations. -class AnimatedMatrix4Value extends AnimatedValue { - AnimatedMatrix4Value(Matrix4 begin, { Matrix4 end, Curve curve, Curve reverseCurve }) - : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); - - Matrix4 lerp(double t) { - // TODO(mpcomplete): Animate the full matrix. Will animating the cells - // separately work? - Vector3 beginT = begin.getTranslation(); - Vector3 endT = end.getTranslation(); - Vector3 lerpT = beginT*(1.0-t) + endT*t; - return new Matrix4.identity()..translate(lerpT); - } -} - -/// A container that gradually changes its values over a period of time. -/// -/// This class is useful for generating simple implicit transitions between -/// different parameters to [Container]. For more complex animations, you'll -/// likely want to use a subclass of [Transition] or control a [Performance] -/// yourself. -class AnimatedContainer extends StatefulComponent { - AnimatedContainer({ - Key key, - this.child, - this.constraints, - this.decoration, - this.foregroundDecoration, - this.margin, - this.padding, - this.transform, - this.width, - this.height, - this.curve: Curves.linear, - this.duration - }) : super(key: key) { - assert(margin == null || margin.isNonNegative); - assert(padding == null || padding.isNonNegative); - assert(decoration == null || decoration.debugAssertValid()); - assert(foregroundDecoration == null || foregroundDecoration.debugAssertValid()); - assert(curve != null); - assert(duration != null); - } - - final Widget child; - - /// Additional constraints to apply to the child. - final BoxConstraints constraints; - - /// The decoration to paint behind the child. - final Decoration decoration; - - /// The decoration to paint in front of the child. - final Decoration foregroundDecoration; - - /// Empty space to surround the decoration. - final EdgeDims margin; - - /// Empty space to inscribe inside the decoration. - final EdgeDims padding; - - /// The transformation matrix to apply before painting the container. - final Matrix4 transform; - - /// If non-null, requires the decoration to have this width. - final double width; - - /// If non-null, requires the decoration to have this height. - final double height; - - /// The curve to apply when animating the parameters of this container. - final Curve curve; - - /// The duration over which to animate the parameters of this container. - final Duration duration; - - _AnimatedContainerState createState() => new _AnimatedContainerState(); -} - -class _AnimatedContainerState extends State { - AnimatedBoxConstraintsValue _constraints; - AnimatedDecorationValue _decoration; - AnimatedDecorationValue _foregroundDecoration; - AnimatedEdgeDimsValue _margin; - AnimatedEdgeDimsValue _padding; - AnimatedMatrix4Value _transform; - AnimatedValue _width; - AnimatedValue _height; - - Performance _performanceController; - PerformanceView _performance; - - void initState() { - super.initState(); - _performanceController = new Performance( - duration: config.duration, - debugLabel: '${config.toStringShort()}' - ); - _updateCurve(); - _configAllVariables(); - } - - void didUpdateConfig(AnimatedContainer oldConfig) { - if (config.curve != oldConfig.curve) - _updateCurve(); - _performanceController.duration = config.duration; - if (_configAllVariables()) { - _updateBeginValue(_constraints); - _updateBeginValue(_decoration); - _updateBeginValue(_foregroundDecoration); - _updateBeginValue(_margin); - _updateBeginValue(_padding); - _updateBeginValue(_transform); - _updateBeginValue(_width); - _updateBeginValue(_height); - _performanceController.progress = 0.0; - _performanceController.play(); - } - } - - void _updateCurve() { - _performance?.removeListener(_updateAllVariables); - if (config.curve != null) - _performance = new CurvedPerformance(_performanceController, curve: config.curve); - else - _performance = _performanceController; - _performance.addListener(_updateAllVariables); - } - - void dispose() { - _performanceController.stop(); - super.dispose(); - } - - void _updateVariable(Animatable variable) { - if (variable != null) - _performance.updateVariable(variable); - } - - void _updateAllVariables() { - setState(() { - _updateVariable(_constraints); - _updateVariable(_decoration); - _updateVariable(_foregroundDecoration); - _updateVariable(_margin); - _updateVariable(_padding); - _updateVariable(_transform); - _updateVariable(_width); - _updateVariable(_height); - }); - } - - bool _updateEndValue(AnimatedValue variable, dynamic targetValue) { - if (targetValue == variable.end) - return false; - variable.end = targetValue; - return true; - } - - void _updateBeginValue(AnimatedValue variable) { - variable?.begin = variable.value; - } - - bool _configAllVariables() { - bool startAnimation = false; - if (config.constraints != null) { - _constraints ??= new AnimatedBoxConstraintsValue(config.constraints); - if (_updateEndValue(_constraints, config.constraints)) - startAnimation = true; - } else { - _constraints = null; - } - - if (config.decoration != null) { - _decoration ??= new AnimatedDecorationValue(config.decoration); - if (_updateEndValue(_decoration, config.decoration)) - startAnimation = true; - } else { - _decoration = null; - } - - if (config.foregroundDecoration != null) { - _foregroundDecoration ??= new AnimatedDecorationValue(config.foregroundDecoration); - if (_updateEndValue(_foregroundDecoration, config.foregroundDecoration)) - startAnimation = true; - } else { - _foregroundDecoration = null; - } - - if (config.margin != null) { - _margin ??= new AnimatedEdgeDimsValue(config.margin); - if (_updateEndValue(_margin, config.margin)) - startAnimation = true; - } else { - _margin = null; - } - - if (config.padding != null) { - _padding ??= new AnimatedEdgeDimsValue(config.padding); - if (_updateEndValue(_padding, config.padding)) - startAnimation = true; - } else { - _padding = null; - } - - if (config.transform != null) { - _transform ??= new AnimatedMatrix4Value(config.transform); - if (_updateEndValue(_transform, config.transform)) - startAnimation = true; - } else { - _transform = null; - } - - if (config.width != null) { - _width ??= new AnimatedValue(config.width); - if (_updateEndValue(_width, config.width)) - startAnimation = true; - } else { - _width = null; - } - - if (config.height != null) { - _height ??= new AnimatedValue(config.height); - if (_updateEndValue(_height, config.height)) - startAnimation = true; - } else { - _height = null; - } - - return startAnimation; - } - - Widget build(BuildContext context) { - return new Container( - child: config.child, - constraints: _constraints?.value, - decoration: _decoration?.value, - foregroundDecoration: _foregroundDecoration?.value, - margin: _margin?.value, - padding: _padding?.value, - transform: _transform?.value, - width: _width?.value, - height: _height?.value - ); - } - - void debugFillDescription(List description) { - super.debugFillDescription(description); - if (_constraints != null) - description.add('has constraints'); - if (_decoration != null) - description.add('has background'); - if (_foregroundDecoration != null) - description.add('has foreground'); - if (_margin != null) - description.add('has margin'); - if (_padding != null) - description.add('has padding'); - if (_transform != null) - description.add('has transform'); - if (_width != null) - description.add('has width'); - if (_height != null) - description.add('has height'); - } -} diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index c6cccd730b..ad6637c678 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -1023,15 +1023,15 @@ class Positioned extends ParentDataWidget { Positioned({ Key key, Widget child, + this.left, this.top, this.right, this.bottom, - this.left, this.width, this.height }) : super(key: key, child: child) { - assert(top == null || bottom == null || height == null); assert(left == null || right == null || width == null); + assert(top == null || bottom == null || height == null); } Positioned.fromRect({ @@ -1046,6 +1046,9 @@ class Positioned extends ParentDataWidget { bottom = null, super(key: key, child: child); + /// The offset of the child's left edge from the left of the stack. + final double left; + /// The offset of the child's top edge from the top of the stack. final double top; @@ -1055,17 +1058,16 @@ class Positioned extends ParentDataWidget { /// The offset of the child's bottom edge from the bottom of the stack. final double bottom; - /// The offset of the child's left edge from the left of the stack. - final double left; - /// The child's width. /// - /// Ignored if both left and right are non-null. + /// Only two out of the three horizontal values (left, right, width) can be + /// set. The third must be null. final double width; /// The child's height. /// - /// Ignored if both top and bottom are non-null. + /// Only two out of the three vertical values (top, bottom, height) can be + /// set. The third must be null. final double height; void applyParentData(RenderObject renderObject) { @@ -1073,6 +1075,11 @@ class Positioned extends ParentDataWidget { final StackParentData parentData = renderObject.parentData; bool needsLayout = false; + if (parentData.left != left) { + parentData.left = left; + needsLayout = true; + } + if (parentData.top != top) { parentData.top = top; needsLayout = true; @@ -1088,11 +1095,6 @@ class Positioned extends ParentDataWidget { needsLayout = true; } - if (parentData.left != left) { - parentData.left = left; - needsLayout = true; - } - if (parentData.width != width) { parentData.width = width; needsLayout = true; diff --git a/packages/flutter/lib/src/widgets/implicit_animations.dart b/packages/flutter/lib/src/widgets/implicit_animations.dart new file mode 100644 index 0000000000..c8e3df2c4e --- /dev/null +++ b/packages/flutter/lib/src/widgets/implicit_animations.dart @@ -0,0 +1,403 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/animation.dart'; + +import 'basic.dart'; +import 'framework.dart'; + +import 'package:vector_math/vector_math_64.dart'; + +/// An animated value that interpolates [BoxConstraint]s. +class AnimatedBoxConstraintsValue extends AnimatedValue { + AnimatedBoxConstraintsValue(BoxConstraints begin, { BoxConstraints end, Curve curve, Curve reverseCurve }) + : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); + + BoxConstraints lerp(double t) => BoxConstraints.lerp(begin, end, t); +} + +/// An animated value that interpolates [Decoration]s. +class AnimatedDecorationValue extends AnimatedValue { + AnimatedDecorationValue(Decoration begin, { Decoration end, Curve curve, Curve reverseCurve }) + : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); + + Decoration lerp(double t) { + if (begin == null && end == null) + return null; + if (end == null) + return begin.lerpTo(end, t); + return end.lerpFrom(begin, t); + } +} + +/// An animated value that interpolates [EdgeDims]. +class AnimatedEdgeDimsValue extends AnimatedValue { + AnimatedEdgeDimsValue(EdgeDims begin, { EdgeDims end, Curve curve, Curve reverseCurve }) + : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); + + EdgeDims lerp(double t) => EdgeDims.lerp(begin, end, t); +} + +/// An animated value that interpolates [Matrix4]s. +/// +/// Currently this class works only for translations. +class AnimatedMatrix4Value extends AnimatedValue { + AnimatedMatrix4Value(Matrix4 begin, { Matrix4 end, Curve curve, Curve reverseCurve }) + : super(begin, end: end, curve: curve, reverseCurve: reverseCurve); + + Matrix4 lerp(double t) { + // TODO(mpcomplete): Animate the full matrix. Will animating the cells + // separately work? + Vector3 beginT = begin.getTranslation(); + Vector3 endT = end.getTranslation(); + Vector3 lerpT = beginT*(1.0-t) + endT*t; + return new Matrix4.identity()..translate(lerpT); + } +} + +/// An abstract widget for building components that gradually change their +/// values over a period of time. +abstract class AnimatedWidgetBase extends StatefulComponent { + AnimatedWidgetBase({ + Key key, + this.curve: Curves.linear, + this.duration + }) : super(key: key) { + assert(curve != null); + assert(duration != null); + } + + /// The curve to apply when animating the parameters of this container. + final Curve curve; + + /// The duration over which to animate the parameters of this container. + final Duration duration; + + AnimatedWidgetBaseState createState(); +} + +typedef AnimatedValue VariableConstructor(T targetValue); +typedef AnimatedValue VariableVisitor(AnimatedValue variable, T targetValue, VariableConstructor constructor); + +abstract class AnimatedWidgetBaseState extends State { + Performance _performanceController; + PerformanceView _performance; + + void initState() { + super.initState(); + _performanceController = new Performance( + duration: config.duration, + debugLabel: '${config.toStringShort()}' + ); + _updateCurve(); + _configAllVariables(); + } + + void didUpdateConfig(T oldConfig) { + if (config.curve != oldConfig.curve) + _updateCurve(); + _performanceController.duration = config.duration; + if (_configAllVariables()) { + forEachVariable((AnimatedValue variable, dynamic targetValue, VariableConstructor constructor) { + _updateBeginValue(variable); return variable; + }); + _performanceController.progress = 0.0; + _performanceController.play(); + } + } + + void _updateCurve() { + _performance?.removeListener(_updateAllVariables); + if (config.curve != null) + _performance = new CurvedPerformance(_performanceController, curve: config.curve); + else + _performance = _performanceController; + _performance.addListener(_updateAllVariables); + } + + void dispose() { + _performanceController.stop(); + super.dispose(); + } + + void _updateVariable(Animatable variable) { + if (variable != null) + _performance.updateVariable(variable); + } + + void _updateAllVariables() { + setState(() { + forEachVariable((AnimatedValue variable, dynamic targetValue, VariableConstructor constructor) { + _updateVariable(variable); return variable; + }); + }); + } + + bool _updateEndValue(AnimatedValue variable, dynamic targetValue) { + if (targetValue == variable.end) + return false; + variable.end = targetValue; + return true; + } + + void _updateBeginValue(AnimatedValue variable) { + variable?.begin = variable.value; + } + + bool _configAllVariables() { + bool startAnimation = false; + forEachVariable((AnimatedValue variable, dynamic targetValue, VariableConstructor constructor) { + if (targetValue != null) { + variable ??= constructor(targetValue); + if (_updateEndValue(variable, targetValue)) + startAnimation = true; + } else { + variable = null; + } + return variable; + }); + return startAnimation; + } + + /// Subclasses must implement this function by running through the following + /// steps for for each animatable facet in the class: + /// + /// 1. Call the visitor callback with three arguments, the first argument + /// being the current value of the AnimatedValue object that represents the + /// variable (initially null), the second argument, of type T, being the value + /// on the Widget (config) that represents the current target value of the + /// variable, and the third being a callback that takes a value T (which will + /// be the second argument to the visitor callback), and that returns an + /// AnimatedValue object for the variable, configured with the given value + /// as the begin value. + /// + /// 2. Take the value returned from the callback, and store it. This is the + /// value to use as the current value the next time that the forEachVariable() + /// method is called. + void forEachVariable(VariableVisitor visitor); +} + +/// A container that gradually changes its values over a period of time. +/// +/// This class is useful for generating simple implicit transitions between +/// different parameters to [Container]. For more complex animations, you'll +/// likely want to use a subclass of [Transition] or control a [Performance] +/// yourself. +class AnimatedContainer extends AnimatedWidgetBase { + AnimatedContainer({ + Key key, + this.child, + this.constraints, + this.decoration, + this.foregroundDecoration, + this.margin, + this.padding, + this.transform, + this.width, + this.height, + Curve curve: Curves.linear, + Duration duration + }) : super(key: key, curve: curve, duration: duration) { + assert(decoration == null || decoration.debugAssertValid()); + assert(foregroundDecoration == null || foregroundDecoration.debugAssertValid()); + assert(margin == null || margin.isNonNegative); + assert(padding == null || padding.isNonNegative); + } + + final Widget child; + + /// Additional constraints to apply to the child. + final BoxConstraints constraints; + + /// The decoration to paint behind the child. + final Decoration decoration; + + /// The decoration to paint in front of the child. + final Decoration foregroundDecoration; + + /// Empty space to surround the decoration. + final EdgeDims margin; + + /// Empty space to inscribe inside the decoration. + final EdgeDims padding; + + /// The transformation matrix to apply before painting the container. + final Matrix4 transform; + + /// If non-null, requires the decoration to have this width. + final double width; + + /// If non-null, requires the decoration to have this height. + final double height; + + _AnimatedContainerState createState() => new _AnimatedContainerState(); +} + +class _AnimatedContainerState extends AnimatedWidgetBaseState { + AnimatedBoxConstraintsValue _constraints; + AnimatedDecorationValue _decoration; + AnimatedDecorationValue _foregroundDecoration; + AnimatedEdgeDimsValue _margin; + AnimatedEdgeDimsValue _padding; + AnimatedMatrix4Value _transform; + AnimatedValue _width; + AnimatedValue _height; + + void forEachVariable(VariableVisitor visitor) { + // TODO(ianh): Use constructor tear-offs when it becomes possible + _constraints = visitor(_constraints, config.constraints, (dynamic value) => new AnimatedBoxConstraintsValue(value)); + _decoration = visitor(_decoration, config.decoration, (dynamic value) => new AnimatedDecorationValue(value)); + _foregroundDecoration = visitor(_foregroundDecoration, config.foregroundDecoration, (dynamic value) => new AnimatedDecorationValue(value)); + _margin = visitor(_margin, config.margin, (dynamic value) => new AnimatedEdgeDimsValue(value)); + _padding = visitor(_padding, config.padding, (dynamic value) => new AnimatedEdgeDimsValue(value)); + _transform = visitor(_transform, config.transform, (dynamic value) => new AnimatedMatrix4Value(value)); + _width = visitor(_width, config.width, (dynamic value) => new AnimatedValue(value)); + _height = visitor(_height, config.height, (dynamic value) => new AnimatedValue(value)); + } + + Widget build(BuildContext context) { + return new Container( + child: config.child, + constraints: _constraints?.value, + decoration: _decoration?.value, + foregroundDecoration: _foregroundDecoration?.value, + margin: _margin?.value, + padding: _padding?.value, + transform: _transform?.value, + width: _width?.value, + height: _height?.value + ); + } + + void debugFillDescription(List description) { + super.debugFillDescription(description); + if (_constraints != null) + description.add('has constraints'); + if (_decoration != null) + description.add('has background'); + if (_foregroundDecoration != null) + description.add('has foreground'); + if (_margin != null) + description.add('has margin'); + if (_padding != null) + description.add('has padding'); + if (_transform != null) + description.add('has transform'); + if (_width != null) + description.add('has width'); + if (_height != null) + description.add('has height'); + } +} + +/// Animated version of [Positioned] which automatically transitions the child's +/// position over a given duration whenever the given positon changes. +/// +/// Only works if it's the child of a [Stack]. +class AnimatedPositioned extends AnimatedWidgetBase { + AnimatedPositioned({ + Key key, + this.child, + this.left, + this.top, + this.right, + this.bottom, + this.width, + this.height, + Curve curve: Curves.linear, + Duration duration + }) : super(key: key, curve: curve, duration: duration) { + assert(left == null || right == null || width == null); + assert(top == null || bottom == null || height == null); + } + + AnimatedPositioned.fromRect({ + Key key, + this.child, + Rect rect, + Curve curve: Curves.linear, + Duration duration + }) : left = rect.left, + top = rect.top, + width = rect.width, + height = rect.height, + right = null, + bottom = null, + super(key: key, curve: curve, duration: duration); + + final Widget child; + + /// The offset of the child's left edge from the left of the stack. + final double left; + + /// The offset of the child's top edge from the top of the stack. + final double top; + + /// The offset of the child's right edge from the right of the stack. + final double right; + + /// The offset of the child's bottom edge from the bottom of the stack. + final double bottom; + + /// The child's width. + /// + /// Only two out of the three horizontal values (left, right, width) can be + /// set. The third must be null. + final double width; + + /// The child's height. + /// + /// Only two out of the three vertical values (top, bottom, height) can be + /// set. The third must be null. + final double height; + + _AnimatedPositionedState createState() => new _AnimatedPositionedState(); +} + +class _AnimatedPositionedState extends AnimatedWidgetBaseState { + AnimatedValue _left; + AnimatedValue _top; + AnimatedValue _right; + AnimatedValue _bottom; + AnimatedValue _width; + AnimatedValue _height; + + void forEachVariable(VariableVisitor visitor) { + // TODO(ianh): Use constructor tear-offs when it becomes possible + _left = visitor(_left, config.left, (dynamic value) => new AnimatedValue(value)); + _top = visitor(_top, config.top, (dynamic value) => new AnimatedValue(value)); + _right = visitor(_right, config.right, (dynamic value) => new AnimatedValue(value)); + _bottom = visitor(_bottom, config.bottom, (dynamic value) => new AnimatedValue(value)); + _width = visitor(_width, config.width, (dynamic value) => new AnimatedValue(value)); + _height = visitor(_height, config.height, (dynamic value) => new AnimatedValue(value)); + } + + Widget build(BuildContext context) { + return new Positioned( + child: config.child, + left: _left?.value, + top: _top?.value, + right: _right?.value, + bottom: _bottom?.value, + width: _width?.value, + height: _height?.value + ); + } + + void debugFillDescription(List description) { + super.debugFillDescription(description); + if (_left != null) + description.add('has left'); + if (_top != null) + description.add('has top'); + if (_right != null) + description.add('has right'); + if (_bottom != null) + description.add('has bottom'); + if (_width != null) + description.add('has width'); + if (_height != null) + description.add('has height'); + } +} diff --git a/packages/flutter/lib/src/widgets/transitions.dart b/packages/flutter/lib/src/widgets/transitions.dart index 76fb71f2fd..401339bebd 100644 --- a/packages/flutter/lib/src/widgets/transitions.dart +++ b/packages/flutter/lib/src/widgets/transitions.dart @@ -226,7 +226,11 @@ class AnimatedRelativeRectValue extends AnimatedValue { RelativeRect lerp(double t) => RelativeRect.lerp(begin, end, t); } -/// Animated version of [Positioned]. +/// Animated version of [Positioned] which takes a specific +/// [AnimatedRelativeRectValue] and a [PerformanceView] to transition the +/// child's position from a start position to and end position over the lifetime +/// of the performance. +/// /// Only works if it's the child of a [Stack]. class PositionedTransition extends TransitionWithChild { PositionedTransition({ diff --git a/packages/flutter/lib/widgets.dart b/packages/flutter/lib/widgets.dart index a5ba6610d1..227b54a5db 100644 --- a/packages/flutter/lib/widgets.dart +++ b/packages/flutter/lib/widgets.dart @@ -5,7 +5,6 @@ /// The Flutter widget framework. library widgets; -export 'src/widgets/animated_container.dart'; export 'src/widgets/basic.dart'; export 'src/widgets/binding.dart'; export 'src/widgets/dismissable.dart'; @@ -18,6 +17,7 @@ export 'src/widgets/gesture_detector.dart'; export 'src/widgets/gridpaper.dart'; export 'src/widgets/heroes.dart'; export 'src/widgets/homogeneous_viewport.dart'; +export 'src/widgets/implicit_animations.dart'; export 'src/widgets/locale_query.dart'; export 'src/widgets/media_query.dart'; export 'src/widgets/mimic.dart'; diff --git a/packages/flutter/test/widget/animated_container_test.dart b/packages/flutter/test/widget/animated_container_test.dart index fac5763fea..a4ba63797b 100644 --- a/packages/flutter/test/widget/animated_container_test.dart +++ b/packages/flutter/test/widget/animated_container_test.dart @@ -30,7 +30,7 @@ void main() { ) ); - RenderDecoratedBox box = key.currentState.context.findRenderObject(); + RenderDecoratedBox box = key.currentContext.findRenderObject(); actualDecoration = box.decoration; expect(actualDecoration.backgroundColor, equals(decorationA.backgroundColor)); @@ -42,7 +42,7 @@ void main() { ) ); - expect(key.currentState.context.findRenderObject(), equals(box)); + expect(key.currentContext.findRenderObject(), equals(box)); actualDecoration = box.decoration; expect(actualDecoration.backgroundColor, equals(decorationA.backgroundColor)); diff --git a/packages/flutter/test/widget/animated_positioned_test.dart b/packages/flutter/test/widget/animated_positioned_test.dart new file mode 100644 index 0000000000..3a3a61234f --- /dev/null +++ b/packages/flutter/test/widget/animated_positioned_test.dart @@ -0,0 +1,215 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; +import 'package:test/test.dart'; + +void main() { + test('AnimatedPositioned - basics', () { + testWidgets((WidgetTester tester) { + GlobalKey key = new GlobalKey(); + + RenderBox box; + + tester.pumpWidget( + new Stack( + [ + new AnimatedPositioned( + child: new Container(key: key), + left: 50.0, + top: 30.0, + width: 70.0, + height: 110.0, + duration: const Duration(seconds: 2) + ) + ] + ) + ); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(50.0 + 70.0 / 2.0, 30.0 + 110.0 / 2.0))); + + tester.pump(const Duration(seconds: 1)); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(50.0 + 70.0 / 2.0, 30.0 + 110.0 / 2.0))); + + tester.pumpWidget( + new Stack( + [ + new AnimatedPositioned( + child: new Container(key: key), + left: 37.0, + top: 31.0, + width: 59.0, + height: 71.0, + duration: const Duration(seconds: 2) + ) + ] + ) + ); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(50.0 + 70.0 / 2.0, 30.0 + 110.0 / 2.0))); + + tester.pump(const Duration(seconds: 1)); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(50.0 - (50.0 - 37.0) / 2.0 + (70.0 - (70.0 - 59.0) / 2.0) / 2.0, + 30.0 + (31.0 - 30.0) / 2.0 + (110.0 - (110.0 - 71.0) / 2.0) / 2.0))); + + tester.pump(const Duration(seconds: 1)); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(37.0 + 59.0 / 2.0, 31.0 + 71.0 / 2.0))); + + }); + }); + + test('AnimatedPositioned - interrupted animation', () { + testWidgets((WidgetTester tester) { + GlobalKey key = new GlobalKey(); + + RenderBox box; + + tester.pumpWidget( + new Stack( + [ + new AnimatedPositioned( + child: new Container(key: key), + left: 0.0, + top: 0.0, + width: 100.0, + height: 100.0, + duration: const Duration(seconds: 2) + ) + ] + ) + ); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(50.0, 50.0))); + + tester.pump(const Duration(seconds: 1)); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(50.0, 50.0))); + + tester.pumpWidget( + new Stack( + [ + new AnimatedPositioned( + child: new Container(key: key), + left: 100.0, + top: 100.0, + width: 100.0, + height: 100.0, + duration: const Duration(seconds: 2) + ) + ] + ) + ); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(50.0, 50.0))); + + tester.pump(const Duration(seconds: 1)); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(100.0, 100.0))); + + tester.pumpWidget( + new Stack( + [ + new AnimatedPositioned( + child: new Container(key: key), + left: 150.0, + top: 150.0, + width: 100.0, + height: 100.0, + duration: const Duration(seconds: 2) + ) + ] + ) + ); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(100.0, 100.0))); + + tester.pump(const Duration(seconds: 1)); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(150.0, 150.0))); + + tester.pump(const Duration(seconds: 1)); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(200.0, 200.0))); + + }); + }); + + test('AnimatedPositioned - switching variables', () { + testWidgets((WidgetTester tester) { + GlobalKey key = new GlobalKey(); + + RenderBox box; + + tester.pumpWidget( + new Stack( + [ + new AnimatedPositioned( + child: new Container(key: key), + left: 0.0, + top: 0.0, + width: 100.0, + height: 100.0, + duration: const Duration(seconds: 2) + ) + ] + ) + ); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(50.0, 50.0))); + + tester.pump(const Duration(seconds: 1)); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(50.0, 50.0))); + + tester.pumpWidget( + new Stack( + [ + new AnimatedPositioned( + child: new Container(key: key), + left: 0.0, + top: 100.0, + right: 100.0, // 700.0 from the left + height: 100.0, + duration: const Duration(seconds: 2) + ) + ] + ) + ); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(350.0, 50.0))); + + tester.pump(const Duration(seconds: 1)); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(350.0, 100.0))); + + tester.pump(const Duration(seconds: 1)); + + box = key.currentContext.findRenderObject(); + expect(box.localToGlobal(box.size.center(Point.origin)), equals(const Point(350.0, 150.0))); + + }); + }); + +}