AnimatedPositioned
This commit is contained in:
parent
f37c29dddd
commit
63c2ac9c4e
@ -290,3 +290,114 @@ class _AnimatedContainerState extends AnimatedWidgetBaseState<AnimatedContainer>
|
|||||||
description.add('has height');
|
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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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