Teach Block how to layout horizontally
We'll need this for horizontally scrolling lists.
This commit is contained in:
parent
5923d03cca
commit
f6c9ab8050
@ -9,6 +9,10 @@ import 'package:sky/rendering/object.dart';
|
|||||||
|
|
||||||
class BlockParentData extends BoxParentData with ContainerParentDataMixin<RenderBox> { }
|
class BlockParentData extends BoxParentData with ContainerParentDataMixin<RenderBox> { }
|
||||||
|
|
||||||
|
enum BlockDirection { horizontal, vertical }
|
||||||
|
|
||||||
|
typedef double _ChildSizingFunction(RenderBox child, BoxConstraints constraints);
|
||||||
|
|
||||||
abstract class RenderBlockBase extends RenderBox with ContainerRenderObjectMixin<RenderBox, BlockParentData>,
|
abstract class RenderBlockBase extends RenderBox with ContainerRenderObjectMixin<RenderBox, BlockParentData>,
|
||||||
RenderBoxContainerDefaultsMixin<RenderBox, BlockParentData> {
|
RenderBoxContainerDefaultsMixin<RenderBox, BlockParentData> {
|
||||||
|
|
||||||
@ -16,8 +20,9 @@ abstract class RenderBlockBase extends RenderBox with ContainerRenderObjectMixin
|
|||||||
// uses the maximum width provided by the parent
|
// uses the maximum width provided by the parent
|
||||||
|
|
||||||
RenderBlockBase({
|
RenderBlockBase({
|
||||||
List<RenderBox> children
|
List<RenderBox> children,
|
||||||
}) {
|
BlockDirection direction: BlockDirection.vertical
|
||||||
|
}) : _direction = direction {
|
||||||
addAll(children);
|
addAll(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,93 +31,127 @@ abstract class RenderBlockBase extends RenderBox with ContainerRenderObjectMixin
|
|||||||
child.parentData = new BlockParentData();
|
child.parentData = new BlockParentData();
|
||||||
}
|
}
|
||||||
|
|
||||||
double _childrenHeight;
|
BlockDirection _direction;
|
||||||
double get childrenHeight => _childrenHeight;
|
BlockDirection get direction => _direction;
|
||||||
|
void set direction (BlockDirection value) {
|
||||||
|
if (_direction != value) {
|
||||||
|
_direction = value;
|
||||||
|
markNeedsLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void markNeedsLayout() {
|
bool get _isVertical => _direction == BlockDirection.vertical;
|
||||||
_childrenHeight = null;
|
|
||||||
super.markNeedsLayout();
|
BoxConstraints _getInnerConstraints(BoxConstraints constraints) {
|
||||||
|
if (_isVertical)
|
||||||
|
return new BoxConstraints.tightFor(width: constraints.constrainWidth(constraints.maxWidth));
|
||||||
|
return new BoxConstraints.tightFor(height: constraints.constrainHeight(constraints.maxHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
void performLayout() {
|
void performLayout() {
|
||||||
assert(constraints is BoxConstraints);
|
BoxConstraints innerConstraints = _getInnerConstraints(constraints);
|
||||||
double width = constraints.constrainWidth(constraints.maxWidth);
|
double position = 0.0;
|
||||||
BoxConstraints innerConstraints = new BoxConstraints.tightFor(width: width);
|
|
||||||
double y = 0.0;
|
|
||||||
RenderBox child = firstChild;
|
RenderBox child = firstChild;
|
||||||
while (child != null) {
|
while (child != null) {
|
||||||
child.layout(innerConstraints, parentUsesSize: true);
|
child.layout(innerConstraints, parentUsesSize: true);
|
||||||
assert(child.parentData is BlockParentData);
|
assert(child.parentData is BlockParentData);
|
||||||
child.parentData.position = new Point(0.0, y);
|
child.parentData.position = _isVertical ? new Point(0.0, position) : new Point(position, 0.0);
|
||||||
y += child.size.height;
|
position += _isVertical ? child.size.height : child.size.width;
|
||||||
child = child.parentData.nextSibling;
|
child = child.parentData.nextSibling;
|
||||||
}
|
}
|
||||||
_childrenHeight = y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class RenderBlock extends RenderBlockBase {
|
class RenderBlock extends RenderBlockBase {
|
||||||
|
|
||||||
// sizes itself to the height of its child stack
|
RenderBlock({
|
||||||
|
List<RenderBox> children,
|
||||||
|
BlockDirection direction: BlockDirection.vertical
|
||||||
|
}) : super(children: children, direction: direction);
|
||||||
|
|
||||||
RenderBlock({ List<RenderBox> children }) : super(children: children);
|
double _getIntrinsicCrossAxis(BoxConstraints constraints, _ChildSizingFunction childSize) {
|
||||||
|
double extent = 0.0;
|
||||||
double getMinIntrinsicWidth(BoxConstraints constraints) {
|
BoxConstraints innerConstraints = _isVertical ? constraints.widthConstraints() : constraints.heightConstraints();
|
||||||
double width = 0.0;
|
|
||||||
BoxConstraints innerConstraints = constraints.widthConstraints();
|
|
||||||
RenderBox child = firstChild;
|
RenderBox child = firstChild;
|
||||||
while (child != null) {
|
while (child != null) {
|
||||||
width = math.max(width, child.getMinIntrinsicWidth(innerConstraints));
|
extent = math.max(extent, childSize(child, innerConstraints));
|
||||||
assert(child.parentData is BlockParentData);
|
assert(child.parentData is BlockParentData);
|
||||||
child = child.parentData.nextSibling;
|
child = child.parentData.nextSibling;
|
||||||
}
|
}
|
||||||
return width;
|
return extent;
|
||||||
|
}
|
||||||
|
|
||||||
|
double _getIntrinsicMainAxis(BoxConstraints constraints) {
|
||||||
|
double extent = 0.0;
|
||||||
|
BoxConstraints innerConstraints = _getInnerConstraints(constraints);
|
||||||
|
RenderBox child = firstChild;
|
||||||
|
while (child != null) {
|
||||||
|
double childExtent = _isVertical ?
|
||||||
|
child.getMinIntrinsicHeight(innerConstraints) :
|
||||||
|
child.getMinIntrinsicWidth(innerConstraints);
|
||||||
|
assert(() {
|
||||||
|
if (_isVertical)
|
||||||
|
return childExtent == child.getMaxIntrinsicHeight(innerConstraints);
|
||||||
|
return childExtent == child.getMaxIntrinsicWidth(innerConstraints);
|
||||||
|
});
|
||||||
|
extent += childExtent;
|
||||||
|
assert(child.parentData is BlockParentData);
|
||||||
|
child = child.parentData.nextSibling;
|
||||||
|
}
|
||||||
|
return extent;
|
||||||
|
}
|
||||||
|
|
||||||
|
double getMinIntrinsicWidth(BoxConstraints constraints) {
|
||||||
|
if (_isVertical) {
|
||||||
|
return _getIntrinsicCrossAxis(constraints,
|
||||||
|
(c, innerConstraints) => c.getMinIntrinsicWidth(innerConstraints));
|
||||||
|
}
|
||||||
|
return _getIntrinsicMainAxis(constraints);
|
||||||
}
|
}
|
||||||
|
|
||||||
double getMaxIntrinsicWidth(BoxConstraints constraints) {
|
double getMaxIntrinsicWidth(BoxConstraints constraints) {
|
||||||
double width = 0.0;
|
if (_isVertical) {
|
||||||
BoxConstraints innerConstraints = constraints.widthConstraints();
|
return _getIntrinsicCrossAxis(constraints,
|
||||||
RenderBox child = firstChild;
|
(c, innerConstraints) => c.getMaxIntrinsicWidth(innerConstraints));
|
||||||
while (child != null) {
|
|
||||||
width = math.max(width, child.getMaxIntrinsicWidth(innerConstraints));
|
|
||||||
assert(child.parentData is BlockParentData);
|
|
||||||
child = child.parentData.nextSibling;
|
|
||||||
}
|
}
|
||||||
return width;
|
return _getIntrinsicMainAxis(constraints);
|
||||||
}
|
|
||||||
|
|
||||||
double _getIntrinsicHeight(BoxConstraints constraints) {
|
|
||||||
double height = 0.0;
|
|
||||||
double width = constraints.constrainWidth(constraints.maxWidth);
|
|
||||||
BoxConstraints innerConstraints = new BoxConstraints.tightFor(width: width);
|
|
||||||
RenderBox child = firstChild;
|
|
||||||
while (child != null) {
|
|
||||||
double childHeight = child.getMinIntrinsicHeight(innerConstraints);
|
|
||||||
assert(childHeight == child.getMaxIntrinsicHeight(innerConstraints));
|
|
||||||
height += childHeight;
|
|
||||||
assert(child.parentData is BlockParentData);
|
|
||||||
child = child.parentData.nextSibling;
|
|
||||||
}
|
|
||||||
return height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double getMinIntrinsicHeight(BoxConstraints constraints) {
|
double getMinIntrinsicHeight(BoxConstraints constraints) {
|
||||||
return _getIntrinsicHeight(constraints);
|
if (_isVertical)
|
||||||
|
return _getIntrinsicMainAxis(constraints);
|
||||||
|
return _getIntrinsicCrossAxis(constraints,
|
||||||
|
(c, innerConstraints) => c.getMinIntrinsicWidth(innerConstraints));
|
||||||
}
|
}
|
||||||
|
|
||||||
double getMaxIntrinsicHeight(BoxConstraints constraints) {
|
double getMaxIntrinsicHeight(BoxConstraints constraints) {
|
||||||
return _getIntrinsicHeight(constraints);
|
if (_isVertical)
|
||||||
|
return _getIntrinsicMainAxis(constraints);
|
||||||
|
return _getIntrinsicCrossAxis(constraints,
|
||||||
|
(c, innerConstraints) => c.getMaxIntrinsicWidth(innerConstraints));
|
||||||
}
|
}
|
||||||
|
|
||||||
double computeDistanceToActualBaseline(TextBaseline baseline) {
|
double computeDistanceToActualBaseline(TextBaseline baseline) {
|
||||||
return defaultComputeDistanceToFirstActualBaseline(baseline);
|
return defaultComputeDistanceToFirstActualBaseline(baseline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double get _mainAxisExtent {
|
||||||
|
RenderBox child = lastChild;
|
||||||
|
if (child == null)
|
||||||
|
return 0.0;
|
||||||
|
BoxParentData parentData = child.parentData;
|
||||||
|
return _isVertical ?
|
||||||
|
parentData.position.y + child.size.height :
|
||||||
|
parentData.position.x + child.size.width;
|
||||||
|
}
|
||||||
|
|
||||||
void performLayout() {
|
void performLayout() {
|
||||||
assert(constraints.maxHeight >= double.INFINITY);
|
assert(_isVertical ? constraints.maxHeight >= double.INFINITY : constraints.maxWidth >= double.INFINITY);
|
||||||
super.performLayout();
|
super.performLayout();
|
||||||
size = constraints.constrain(new Size(constraints.maxWidth, childrenHeight));
|
size = _isVertical ?
|
||||||
|
constraints.constrain(new Size(constraints.maxWidth, _mainAxisExtent)) :
|
||||||
|
constraints.constrain(new Size(_mainAxisExtent, constraints.maxHeight));
|
||||||
assert(!size.isInfinite);
|
assert(!size.isInfinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user