Commit e04135e9 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Change the definition of MainAxisSize (#5931)

This property now applies only to the free space in the flex layout (i.e.,
minimize or maximize the amount of free space). Previously, the flexible
children were always allocated a size of zero when MainAxisSize was min. Now
they're allocated the same size that would be if the MainAxisSize was max.
parent 9ec3cabf
......@@ -40,16 +40,29 @@ class FlexParentData extends ContainerBoxParentDataMixin<RenderBox> {
String toString() => '${super.toString()}; flex=$flex';
}
/// The incoming constraint parameter that defines how much space is available
/// along the main axis in a flex layout. Flex layouts allocate the difference
/// between the available space and the sum of the sizes of the children
/// which are not flexible to the layout's flexible children and the space
/// around the children. See [Row], [Column], [MainAxisAlignment], [Flexible].
/// How much space space should be occupied in the main axis.
///
/// During a flex layout, available space along the main axis is allocated to
/// children. After allocating space, there might be some remaining free space.
/// This value controls whether to maximize or minimize the amount of free
/// space, subject to the incoming layout contraints.
///
/// See [Row], [Column], [MainAxisAlignment], [Flexible].
enum MainAxisSize {
/// The available space is defined by the incoming constraint's min parameter.
/// Minimize the amount of free space along the main axis, subject to the
/// incoming layout constraints.
///
/// If the incoming layout constraints have a large enough
/// [BoxConstraints.minWidth] or [BoxConstraints.minHeight], there might still
/// be a non-zero amount of free space.
min,
/// The available space is defined by the incoming constraint's max parameter.
/// Maximize the amount of free space along the main axis, subject to the
/// incoming layout constraints.
///
/// If the incoming layout constraints have a small enough
/// [BoxConstraints.maxWidth] or [BoxConstraints.maxHeight], there might still
/// be no free space.
max,
}
......@@ -152,7 +165,16 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
}
}
/// The limit used to compute free space along the main axis.
/// How much space space should be occupied in the main axis.
///
/// After allocating space to children, there might be some remaining free
/// space. This value controls whether to maximize or minimize the amount of
/// free space, subject to the incoming layout contraints.
///
/// If some children have a non-zero flex factors (and none have a fit of
/// [FlexFit.loose]), they will expand to consume all the available space and
/// there will be no remaining free space to maximize or minimize, making this
/// value irrelevant to the final layout.
MainAxisSize get mainAxisSize => _mainAxisSize;
MainAxisSize _mainAxisSize;
set mainAxisSize (MainAxisSize value) {
......@@ -339,11 +361,8 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
int totalFlex = 0;
int totalChildren = 0;
assert(constraints != null);
final bool isHorizontal = _direction == Axis.horizontal;
final double minMainSize = isHorizontal ? constraints.minWidth : constraints.minHeight;
final double maxMainSize = isHorizontal ? constraints.maxWidth : constraints.maxHeight;
final double availableSize = mainAxisSize == MainAxisSize.max ? maxMainSize : minMainSize;
final bool canFlex = availableSize < double.INFINITY;
final double maxMainSize = _direction == Axis.horizontal ? constraints.maxWidth : constraints.maxHeight;
final bool canFlex = maxMainSize < double.INFINITY;
double crossSize = 0.0;
double allocatedSize = 0.0; // Sum of the sizes of the the non-flexible children.
......@@ -359,7 +378,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
final String dimension = _direction == Axis.horizontal ? 'width' : 'height';
String error, message;
String addendum = '';
if (availableSize == double.INFINITY) {
if (maxMainSize == double.INFINITY) {
error = 'RenderFlex children have non-zero flex but incoming $dimension constraints are unbounded.';
message = 'When a $identity is in a parent that does not provide a finite $dimension constraint, for example '
'if it is in a $axis scrollable, it will try to shrink-wrap its children along the $axis '
......@@ -445,9 +464,8 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
_overflow = math.max(0.0, allocatedSize - (canFlex ? maxMainSize : 0.0));
// Distribute free space to flexible children, and determine baseline.
final double freeSpace = math.max(0.0, (canFlex ? availableSize : 0.0) - allocatedSize);
final double freeSpace = math.max(0.0, (canFlex ? maxMainSize : 0.0) - allocatedSize);
double maxBaselineDistance = 0.0;
double usedSpace = 0.0;
if (totalFlex > 0 || crossAxisAlignment == CrossAxisAlignment.baseline) {
final double spacePerFlex = totalFlex > 0 ? (freeSpace / totalFlex) : 0.0;
child = firstChild;
......@@ -496,7 +514,7 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
}
}
child.layout(innerConstraints, parentUsesSize: true);
usedSpace += _getMainSize(child);
allocatedSize += _getMainSize(child);
crossSize = math.max(crossSize, _getCrossSize(child));
}
if (crossAxisAlignment == CrossAxisAlignment.baseline) {
......@@ -521,21 +539,21 @@ class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, Fl
if (canFlex) {
final bool isMainAxisSizeMax = mainAxisSize == MainAxisSize.max;
final double preferredSize = isMainAxisSizeMax ? maxMainSize : allocatedSize;
remainingSpace = math.max(0.0, freeSpace - usedSpace);
switch (_direction) {
case Axis.horizontal:
size = constraints.constrain(new Size(preferredSize, crossSize));
remainingSpace = math.max(0.0, size.width - allocatedSize);
crossSize = size.height;
assert(isMainAxisSizeMax ? size.width == maxMainSize : size.width >= minMainSize);
assert(isMainAxisSizeMax ? size.width == maxMainSize : size.width >= constraints.minWidth);
break;
case Axis.vertical:
size = constraints.constrain(new Size(crossSize, preferredSize));
remainingSpace = math.max(0.0, size.height - allocatedSize);
crossSize = size.width;
assert(isMainAxisSizeMax ? size.height == maxMainSize : size.height >= minMainSize);
assert(isMainAxisSizeMax ? size.height == maxMainSize : size.height >= constraints.minHeight);
break;
}
} else {
assert(mainAxisSize == MainAxisSize.max);
leadingSpace = 0.0;
betweenSpace = 0.0;
switch (_direction) {
......
......@@ -1856,15 +1856,16 @@ class Flex extends MultiChildRenderObjectWidget {
/// How the children should be placed along the main axis.
final MainAxisAlignment mainAxisAlignment;
/// The limit that defines how much space is available along the main axis.
///
/// By default the size of this widget will be as big as the incoming
/// max constraint. In other words it will become as big as possible
/// along its main axis by growing [Flexible] children and inserting
/// space between children per the [mainAxisAlignment] parameter.
/// If mainAxisSize is [MainAxisSize.min] then this widget's size along
/// the main axis will be as small as possible. This version of the layout
/// is sometimes referred to as "shrink wrapping".
/// How much space space should be occupied in the main axis.
///
/// After allocating space to children, there might be some remaining free
/// space. This value controls whether to maximize or minimize the amount of
/// free space, subject to the incoming layout contraints.
///
/// If some children have a non-zero flex factors (and none have a fit of
/// [FlexFit.loose]), they will expand to consume all the available space and
/// there will be no remaining free space to maximize or minimize, making this
/// value irrelevant to the final layout.
final MainAxisSize mainAxisSize;
/// How the children should be placed along the cross axis.
......
......@@ -194,6 +194,7 @@ void main() {
}
setFit(box1, FlexFit.loose);
flex.markNeedsLayout();
pumpFrame();
expect(getOffset(box1).dx, equals(0.0));
......@@ -213,4 +214,59 @@ void main() {
expect(getOffset(box3).dx, equals(400.0));
expect(box3.size.width, equals(100.0));
});
test('Flexible with MainAxisSize.min', () {
RenderConstrainedBox box1 = new RenderConstrainedBox(additionalConstraints: new BoxConstraints.tightFor(width: 100.0, height: 100.0));
RenderConstrainedBox box2 = new RenderConstrainedBox(additionalConstraints: new BoxConstraints.tightFor(width: 100.0, height: 100.0));
RenderConstrainedBox box3 = new RenderConstrainedBox(additionalConstraints: new BoxConstraints.tightFor(width: 100.0, height: 100.0));
RenderFlex flex = new RenderFlex(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceBetween
);
flex.addAll(<RenderBox>[box1, box2, box3]);
layout(flex, constraints: const BoxConstraints(
minWidth: 0.0, maxWidth: 500.0, minHeight: 0.0, maxHeight: 400.0)
);
Offset getOffset(RenderBox box) {
FlexParentData parentData = box.parentData;
return parentData.offset;
}
expect(getOffset(box1).dx, equals(0.0));
expect(box1.size.width, equals(100.0));
expect(getOffset(box2).dx, equals(100.0));
expect(box2.size.width, equals(100.0));
expect(getOffset(box3).dx, equals(200.0));
expect(box3.size.width, equals(100.0));
expect(flex.size.width, equals(300.0));
void setFit(RenderBox box, FlexFit fit) {
FlexParentData parentData = box.parentData;
parentData.flex = 1;
parentData.fit = fit;
}
setFit(box1, FlexFit.tight);
flex.markNeedsLayout();
pumpFrame();
expect(getOffset(box1).dx, equals(0.0));
expect(box1.size.width, equals(300.0));
expect(getOffset(box2).dx, equals(300.0));
expect(box2.size.width, equals(100.0));
expect(getOffset(box3).dx, equals(400.0));
expect(box3.size.width, equals(100.0));
expect(flex.size.width, equals(500.0));
setFit(box1, FlexFit.loose);
flex.markNeedsLayout();
pumpFrame();
expect(getOffset(box1).dx, equals(0.0));
expect(box1.size.width, equals(100.0));
expect(getOffset(box2).dx, equals(100.0));
expect(box2.size.width, equals(100.0));
expect(getOffset(box3).dx, equals(200.0));
expect(box3.size.width, equals(100.0));
expect(flex.size.width, equals(300.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