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