Merge pull request #1164 from Hixie/AnimatedPositioned
AnimatedPositioned
This commit is contained in:
commit
a03382033d
@ -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<BoxConstraints> {
|
|
||||||
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<Decoration> {
|
|
||||||
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<EdgeDims> {
|
|
||||||
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<Matrix4> {
|
|
||||||
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<AnimatedContainer> {
|
|
||||||
AnimatedBoxConstraintsValue _constraints;
|
|
||||||
AnimatedDecorationValue _decoration;
|
|
||||||
AnimatedDecorationValue _foregroundDecoration;
|
|
||||||
AnimatedEdgeDimsValue _margin;
|
|
||||||
AnimatedEdgeDimsValue _padding;
|
|
||||||
AnimatedMatrix4Value _transform;
|
|
||||||
AnimatedValue<double> _width;
|
|
||||||
AnimatedValue<double> _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<double>(config.width);
|
|
||||||
if (_updateEndValue(_width, config.width))
|
|
||||||
startAnimation = true;
|
|
||||||
} else {
|
|
||||||
_width = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.height != null) {
|
|
||||||
_height ??= new AnimatedValue<double>(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<String> 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');
|
|
||||||
}
|
|
||||||
}
|
|
@ -1023,15 +1023,15 @@ class Positioned extends ParentDataWidget<StackRenderObjectWidgetBase> {
|
|||||||
Positioned({
|
Positioned({
|
||||||
Key key,
|
Key key,
|
||||||
Widget child,
|
Widget child,
|
||||||
|
this.left,
|
||||||
this.top,
|
this.top,
|
||||||
this.right,
|
this.right,
|
||||||
this.bottom,
|
this.bottom,
|
||||||
this.left,
|
|
||||||
this.width,
|
this.width,
|
||||||
this.height
|
this.height
|
||||||
}) : super(key: key, child: child) {
|
}) : super(key: key, child: child) {
|
||||||
assert(top == null || bottom == null || height == null);
|
|
||||||
assert(left == null || right == null || width == null);
|
assert(left == null || right == null || width == null);
|
||||||
|
assert(top == null || bottom == null || height == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Positioned.fromRect({
|
Positioned.fromRect({
|
||||||
@ -1046,6 +1046,9 @@ class Positioned extends ParentDataWidget<StackRenderObjectWidgetBase> {
|
|||||||
bottom = null,
|
bottom = null,
|
||||||
super(key: key, child: child);
|
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.
|
/// The offset of the child's top edge from the top of the stack.
|
||||||
final double top;
|
final double top;
|
||||||
|
|
||||||
@ -1055,17 +1058,16 @@ class Positioned extends ParentDataWidget<StackRenderObjectWidgetBase> {
|
|||||||
/// The offset of the child's bottom edge from the bottom of the stack.
|
/// The offset of the child's bottom edge from the bottom of the stack.
|
||||||
final double bottom;
|
final double bottom;
|
||||||
|
|
||||||
/// The offset of the child's left edge from the left of the stack.
|
|
||||||
final double left;
|
|
||||||
|
|
||||||
/// The child's width.
|
/// 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;
|
final double width;
|
||||||
|
|
||||||
/// The child's height.
|
/// 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;
|
final double height;
|
||||||
|
|
||||||
void applyParentData(RenderObject renderObject) {
|
void applyParentData(RenderObject renderObject) {
|
||||||
@ -1073,6 +1075,11 @@ class Positioned extends ParentDataWidget<StackRenderObjectWidgetBase> {
|
|||||||
final StackParentData parentData = renderObject.parentData;
|
final StackParentData parentData = renderObject.parentData;
|
||||||
bool needsLayout = false;
|
bool needsLayout = false;
|
||||||
|
|
||||||
|
if (parentData.left != left) {
|
||||||
|
parentData.left = left;
|
||||||
|
needsLayout = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (parentData.top != top) {
|
if (parentData.top != top) {
|
||||||
parentData.top = top;
|
parentData.top = top;
|
||||||
needsLayout = true;
|
needsLayout = true;
|
||||||
@ -1088,11 +1095,6 @@ class Positioned extends ParentDataWidget<StackRenderObjectWidgetBase> {
|
|||||||
needsLayout = true;
|
needsLayout = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parentData.left != left) {
|
|
||||||
parentData.left = left;
|
|
||||||
needsLayout = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentData.width != width) {
|
if (parentData.width != width) {
|
||||||
parentData.width = width;
|
parentData.width = width;
|
||||||
needsLayout = true;
|
needsLayout = true;
|
||||||
|
403
packages/flutter/lib/src/widgets/implicit_animations.dart
Normal file
403
packages/flutter/lib/src/widgets/implicit_animations.dart
Normal file
@ -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<BoxConstraints> {
|
||||||
|
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<Decoration> {
|
||||||
|
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<EdgeDims> {
|
||||||
|
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<Matrix4> {
|
||||||
|
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<T> VariableConstructor<T>(T targetValue);
|
||||||
|
typedef AnimatedValue<T> VariableVisitor<T>(AnimatedValue<T> variable, T targetValue, VariableConstructor<T> constructor);
|
||||||
|
|
||||||
|
abstract class AnimatedWidgetBaseState<T extends AnimatedWidgetBase> extends State<T> {
|
||||||
|
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<T> 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<T> 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<T> 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<T> 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<T> 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<AnimatedContainer> {
|
||||||
|
AnimatedBoxConstraintsValue _constraints;
|
||||||
|
AnimatedDecorationValue _decoration;
|
||||||
|
AnimatedDecorationValue _foregroundDecoration;
|
||||||
|
AnimatedEdgeDimsValue _margin;
|
||||||
|
AnimatedEdgeDimsValue _padding;
|
||||||
|
AnimatedMatrix4Value _transform;
|
||||||
|
AnimatedValue<double> _width;
|
||||||
|
AnimatedValue<double> _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<double>(value));
|
||||||
|
_height = visitor(_height, config.height, (dynamic value) => new AnimatedValue<double>(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<String> 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<AnimatedPositioned> {
|
||||||
|
AnimatedValue<double> _left;
|
||||||
|
AnimatedValue<double> _top;
|
||||||
|
AnimatedValue<double> _right;
|
||||||
|
AnimatedValue<double> _bottom;
|
||||||
|
AnimatedValue<double> _width;
|
||||||
|
AnimatedValue<double> _height;
|
||||||
|
|
||||||
|
void forEachVariable(VariableVisitor visitor) {
|
||||||
|
// TODO(ianh): Use constructor tear-offs when it becomes possible
|
||||||
|
_left = visitor(_left, config.left, (dynamic value) => new AnimatedValue<double>(value));
|
||||||
|
_top = visitor(_top, config.top, (dynamic value) => new AnimatedValue<double>(value));
|
||||||
|
_right = visitor(_right, config.right, (dynamic value) => new AnimatedValue<double>(value));
|
||||||
|
_bottom = visitor(_bottom, config.bottom, (dynamic value) => new AnimatedValue<double>(value));
|
||||||
|
_width = visitor(_width, config.width, (dynamic value) => new AnimatedValue<double>(value));
|
||||||
|
_height = visitor(_height, config.height, (dynamic value) => new AnimatedValue<double>(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<String> 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');
|
||||||
|
}
|
||||||
|
}
|
@ -226,7 +226,11 @@ class AnimatedRelativeRectValue extends AnimatedValue<RelativeRect> {
|
|||||||
RelativeRect lerp(double t) => RelativeRect.lerp(begin, end, t);
|
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].
|
/// Only works if it's the child of a [Stack].
|
||||||
class PositionedTransition extends TransitionWithChild {
|
class PositionedTransition extends TransitionWithChild {
|
||||||
PositionedTransition({
|
PositionedTransition({
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
/// The Flutter widget framework.
|
/// The Flutter widget framework.
|
||||||
library widgets;
|
library widgets;
|
||||||
|
|
||||||
export 'src/widgets/animated_container.dart';
|
|
||||||
export 'src/widgets/basic.dart';
|
export 'src/widgets/basic.dart';
|
||||||
export 'src/widgets/binding.dart';
|
export 'src/widgets/binding.dart';
|
||||||
export 'src/widgets/dismissable.dart';
|
export 'src/widgets/dismissable.dart';
|
||||||
@ -18,6 +17,7 @@ export 'src/widgets/gesture_detector.dart';
|
|||||||
export 'src/widgets/gridpaper.dart';
|
export 'src/widgets/gridpaper.dart';
|
||||||
export 'src/widgets/heroes.dart';
|
export 'src/widgets/heroes.dart';
|
||||||
export 'src/widgets/homogeneous_viewport.dart';
|
export 'src/widgets/homogeneous_viewport.dart';
|
||||||
|
export 'src/widgets/implicit_animations.dart';
|
||||||
export 'src/widgets/locale_query.dart';
|
export 'src/widgets/locale_query.dart';
|
||||||
export 'src/widgets/media_query.dart';
|
export 'src/widgets/media_query.dart';
|
||||||
export 'src/widgets/mimic.dart';
|
export 'src/widgets/mimic.dart';
|
||||||
|
@ -30,7 +30,7 @@ void main() {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
RenderDecoratedBox box = key.currentState.context.findRenderObject();
|
RenderDecoratedBox box = key.currentContext.findRenderObject();
|
||||||
actualDecoration = box.decoration;
|
actualDecoration = box.decoration;
|
||||||
expect(actualDecoration.backgroundColor, equals(decorationA.backgroundColor));
|
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;
|
actualDecoration = box.decoration;
|
||||||
expect(actualDecoration.backgroundColor, equals(decorationA.backgroundColor));
|
expect(actualDecoration.backgroundColor, equals(decorationA.backgroundColor));
|
||||||
|
|
||||||
|
215
packages/flutter/test/widget/animated_positioned_test.dart
Normal file
215
packages/flutter/test/widget/animated_positioned_test.dart
Normal file
@ -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(
|
||||||
|
<Widget>[
|
||||||
|
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(
|
||||||
|
<Widget>[
|
||||||
|
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(
|
||||||
|
<Widget>[
|
||||||
|
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(
|
||||||
|
<Widget>[
|
||||||
|
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(
|
||||||
|
<Widget>[
|
||||||
|
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(
|
||||||
|
<Widget>[
|
||||||
|
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(
|
||||||
|
<Widget>[
|
||||||
|
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)));
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user