Commit c769d120 authored by Adam Barth's avatar Adam Barth

Add a Positioned constructor from a Rect

A common pattern is to use a Positioned with a Sized box to give both an offset
from the edge as well as a fixed size to the child. This patch rolls into into
the Stack layout algorithm for simplicity.

Fixes #250
parent 6f0464c0
......@@ -54,12 +54,10 @@ class Marker extends StatelessComponent {
return new Positioned(
left: position.x - size / 2.0,
top: position.y - size / 2.0,
width: size,
height: size,
child: new IgnorePointer(
child: new Container(
width: size,
height: size,
child: new CustomPaint(onPaint: paintMarker)
)
child: new CustomPaint(onPaint: paintMarker)
)
);
}
......
......@@ -137,18 +137,28 @@ class RelativeRect {
/// Parent data for use with [RenderStack]
class StackParentData extends ContainerBoxParentDataMixin<RenderBox> {
/// 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.
double top;
/// The offset of the child's right edge from the right of the stack
/// The offset of the child's right edge from the right of the stack.
double right;
/// 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.
double bottom;
/// The offset of the child's left edge from the left of the stack
/// The offset of the child's left edge from the left of the stack.
double left;
/// The child's width.
///
/// Ignored if both left and right are non-null.
double width;
/// The child's height.
///
/// Ignored if both top and bottom are non-null.
double height;
/// Get or set the current values in terms of a RelativeRect object.
RelativeRect get rect => new RelativeRect.fromLTRB(left, top, right, bottom);
void set rect(RelativeRect value) {
......@@ -167,6 +177,10 @@ class StackParentData extends ContainerBoxParentDataMixin<RenderBox> {
bottom = other.bottom;
if (other.left != null)
left = other.left;
if (other.width != null)
width = other.width;
if (other.height != null)
height = other.height;
super.merge(other);
}
......@@ -176,7 +190,7 @@ class StackParentData extends ContainerBoxParentDataMixin<RenderBox> {
/// are non-null. Positioned children do not factor into determining the size
/// of the stack but are instead placed relative to the non-positioned
/// children in the stack.
bool get isPositioned => top != null || right != null || bottom != null || left != null;
bool get isPositioned => top != null || right != null || bottom != null || left != null || width != null || height != null;
String toString() => '${super.toString()}; top=$top; right=$right; bottom=$bottom, left=$left';
}
......@@ -325,9 +339,13 @@ abstract class RenderStackBase extends RenderBox
if (childParentData.left != null && childParentData.right != null)
childConstraints = childConstraints.tightenWidth(size.width - childParentData.right - childParentData.left);
else if (childParentData.width != null)
childConstraints = childConstraints.tightenWidth(childParentData.width);
if (childParentData.top != null && childParentData.bottom != null)
childConstraints = childConstraints.tightenHeight(size.height - childParentData.bottom - childParentData.top);
else if (childParentData.height != null)
childConstraints = childConstraints.tightenHeight(childParentData.height);
child.layout(childConstraints, parentUsesSize: true);
......
......@@ -733,14 +733,32 @@ class Positioned extends ParentDataWidget {
this.top,
this.right,
this.bottom,
this.left
}) : super(key: key, child: child);
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);
}
Positioned.fromRect({
Key key,
Widget child,
Rect rect
}) : left = rect.left,
top = rect.top,
width = rect.width,
height = rect.height,
super(key: key, child: child);
final double top;
final double right;
final double bottom;
final double left;
final double width;
final double height;
void debugValidateAncestor(Widget ancestor) {
assert(() {
'Positioned must placed inside a Stack';
......@@ -773,6 +791,16 @@ class Positioned extends ParentDataWidget {
needsLayout = true;
}
if (parentData.width != width) {
parentData.width = width;
needsLayout = true;
}
if (parentData.height != height) {
parentData.height = height;
needsLayout = true;
}
if (needsLayout) {
AbstractNode targetParent = renderObject.parent;
if (targetParent is RenderObject)
......@@ -790,6 +818,10 @@ class Positioned extends ParentDataWidget {
description.add('right: $right');
if (bottom != null)
description.add('bottom: $bottom');
if (width != null)
description.add('width: $width');
if (height != null)
description.add('height: $height');
}
}
......
......@@ -47,6 +47,8 @@ void main() {
expect(parentData.right, isNull);
expect(parentData.bottom, isNull);
expect(parentData.left, equals(10.0));
expect(parentData.width, isNull);
expect(parentData.height, isNull);
tester.pumpWidget(
new Stack(<Widget>[
......@@ -67,6 +69,8 @@ void main() {
expect(parentData.right, equals(10.0));
expect(parentData.bottom, isNull);
expect(parentData.left, isNull);
expect(parentData.width, isNull);
expect(parentData.height, isNull);
});
});
......@@ -84,6 +88,8 @@ void main() {
expect(parentData.right, isNull);
expect(parentData.bottom, isNull);
expect(parentData.left, equals(10.0));
expect(parentData.width, isNull);
expect(parentData.height, isNull);
tester.pumpWidget(new Stack(<Widget>[ container ]));
containerElement = tester.findElementByKey(key);
......@@ -93,6 +99,8 @@ void main() {
expect(parentData.right, isNull);
expect(parentData.bottom, isNull);
expect(parentData.left, isNull);
expect(parentData.width, isNull);
expect(parentData.height, isNull);
});
});
......@@ -187,4 +195,68 @@ void main() {
});
});
test('Can set width and height', () {
testWidgets((WidgetTester tester) {
Key key = new Key('container');
BoxDecoration kBoxDecoration = new BoxDecoration(
backgroundColor: new Color(0xFF00FF00)
);
tester.pumpWidget(
new Stack(<Widget>[
new Positioned(
left: 10.0,
width: 11.0,
height: 12.0,
child: new DecoratedBox(key: key, decoration: kBoxDecoration)
)
])
);
Element box;
RenderBox renderBox;
StackParentData parentData;
box = tester.findElementByKey(key);
renderBox = box.renderObject;
parentData = renderBox.parentData;
expect(parentData.top, isNull);
expect(parentData.right, isNull);
expect(parentData.bottom, isNull);
expect(parentData.left, equals(10.0));
expect(parentData.width, equals(11.0));
expect(parentData.height, equals(12.0));
expect(parentData.position.x, equals(10.0));
expect(parentData.position.y, equals(0.0));
expect(renderBox.size.width, equals(11.0));
expect(renderBox.size.height, equals(12.0));
tester.pumpWidget(
new Stack(<Widget>[
new Positioned(
right: 10.0,
width: 11.0,
height: 12.0,
child: new DecoratedBox(key: key, decoration: kBoxDecoration)
)
])
);
box = tester.findElementByKey(key);
renderBox = box.renderObject;
parentData = renderBox.parentData;
expect(parentData.top, isNull);
expect(parentData.right, equals(10.0));
expect(parentData.bottom, isNull);
expect(parentData.left, isNull);
expect(parentData.width, equals(11.0));
expect(parentData.height, equals(12.0));
expect(parentData.position.x, equals(779.0));
expect(parentData.position.y, equals(0.0));
expect(renderBox.size.width, equals(11.0));
expect(renderBox.size.height, equals(12.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