layout method
void
layout(
- Context context,
- BoxConstraints constraints, {
- bool parentUsesSize = false,
override
First widget pass to calculate the children layout and bounding box
Implementation
@override
void layout(Context context, BoxConstraints constraints,
{bool parentUsesSize = false}) {
// Determine used flex factor, size inflexible items, calculate free space.
var totalFlex = 0;
Widget? lastFlexChild;
final maxMainSize = direction == Axis.horizontal
? constraints.maxWidth
: constraints.maxHeight;
final canFlex = maxMainSize < double.infinity;
var crossSize = 0.0;
var allocatedSize = 0.0; // Sum of the sizes of the non-flexible children.
var index = _context.firstChild;
for (final child in children.sublist(_context.firstChild)) {
final flex = child is Flexible ? child.flex : 0;
final fit = child is Flexible ? child.fit : FlexFit.loose;
if (flex > 0) {
assert(() {
final dimension = direction == Axis.horizontal ? 'width' : 'height';
if (!canFlex &&
(mainAxisSize == MainAxisSize.max || fit == FlexFit.tight)) {
throw Exception(
'Flex children have non-zero flex but incoming $dimension constraints are unbounded.');
} else {
return true;
}
}());
totalFlex += flex;
} else {
BoxConstraints? innerConstraints;
if (crossAxisAlignment == CrossAxisAlignment.stretch) {
switch (direction) {
case Axis.horizontal:
innerConstraints = BoxConstraints(
minHeight: constraints.maxHeight,
maxHeight: constraints.maxHeight);
break;
case Axis.vertical:
innerConstraints = BoxConstraints(
minWidth: constraints.maxWidth,
maxWidth: constraints.maxWidth);
break;
}
} else {
switch (direction) {
case Axis.horizontal:
innerConstraints =
BoxConstraints(maxHeight: constraints.maxHeight);
break;
case Axis.vertical:
innerConstraints = BoxConstraints(maxWidth: constraints.maxWidth);
break;
}
}
child.layout(context, innerConstraints, parentUsesSize: true);
assert(child.box != null);
allocatedSize += _getMainSize(child);
crossSize = math.max(crossSize, _getCrossSize(child));
if (direction == Axis.vertical &&
allocatedSize > constraints.maxHeight) {
break;
}
}
lastFlexChild = child;
index++;
}
_context.lastChild = index;
final totalChildren = _context.lastChild - _context.firstChild;
// Distribute free space to flexible children, and determine baseline.
final freeSpace =
math.max(0.0, (canFlex ? maxMainSize : 0.0) - allocatedSize);
var allocatedFlexSpace = 0.0;
if (totalFlex > 0) {
final spacePerFlex =
canFlex && totalFlex > 0 ? (freeSpace / totalFlex) : double.nan;
for (final child in children) {
final flex = child is Flexible ? child.flex : 0;
final fit = child is Flexible ? child.fit : FlexFit.loose;
if (flex > 0) {
final maxChildExtent = canFlex
? (child == lastFlexChild
? (freeSpace - allocatedFlexSpace)
: spacePerFlex * flex)
: double.infinity;
double? minChildExtent;
switch (fit) {
case FlexFit.tight:
assert(maxChildExtent < double.infinity);
minChildExtent = maxChildExtent;
break;
case FlexFit.loose:
minChildExtent = 0.0;
break;
}
BoxConstraints? innerConstraints;
if (crossAxisAlignment == CrossAxisAlignment.stretch) {
switch (direction) {
case Axis.horizontal:
innerConstraints = BoxConstraints(
minWidth: minChildExtent,
maxWidth: maxChildExtent,
minHeight: constraints.maxHeight,
maxHeight: constraints.maxHeight);
break;
case Axis.vertical:
innerConstraints = BoxConstraints(
minWidth: constraints.maxWidth,
maxWidth: constraints.maxWidth,
minHeight: minChildExtent,
maxHeight: maxChildExtent);
break;
}
} else {
switch (direction) {
case Axis.horizontal:
innerConstraints = BoxConstraints(
minWidth: minChildExtent,
maxWidth: maxChildExtent,
maxHeight: constraints.maxHeight);
break;
case Axis.vertical:
innerConstraints = BoxConstraints(
maxWidth: constraints.maxWidth,
minHeight: minChildExtent,
maxHeight: maxChildExtent);
break;
}
}
child.layout(context, innerConstraints, parentUsesSize: true);
assert(child.box != null);
final childSize = _getMainSize(child);
assert(childSize <= maxChildExtent);
allocatedSize += childSize;
allocatedFlexSpace += maxChildExtent;
crossSize = math.max(crossSize, _getCrossSize(child));
}
}
}
// Align items along the main axis.
final idealSize = canFlex && mainAxisSize == MainAxisSize.max
? maxMainSize
: allocatedSize;
double? actualSize;
double actualSizeDelta;
late PdfPoint size;
switch (direction) {
case Axis.horizontal:
size = constraints.constrain(PdfPoint(idealSize, crossSize));
actualSize = size.x;
crossSize = size.y;
break;
case Axis.vertical:
size = constraints.constrain(PdfPoint(crossSize, idealSize));
actualSize = size.y;
crossSize = size.x;
break;
}
box = PdfRect.fromPoints(PdfPoint.zero, size);
actualSizeDelta = actualSize - allocatedSize;
final remainingSpace = math.max(0.0, actualSizeDelta);
double? leadingSpace;
late double betweenSpace;
final flipMainAxis = (verticalDirection == VerticalDirection.down &&
direction == Axis.vertical) ||
(verticalDirection == VerticalDirection.up &&
direction == Axis.horizontal);
switch (mainAxisAlignment) {
case MainAxisAlignment.start:
leadingSpace = 0.0;
betweenSpace = 0.0;
break;
case MainAxisAlignment.end:
leadingSpace = remainingSpace;
betweenSpace = 0.0;
break;
case MainAxisAlignment.center:
leadingSpace = remainingSpace / 2.0;
betweenSpace = 0.0;
break;
case MainAxisAlignment.spaceBetween:
leadingSpace = 0.0;
betweenSpace =
totalChildren > 1 ? remainingSpace / (totalChildren - 1) : 0.0;
break;
case MainAxisAlignment.spaceAround:
betweenSpace = totalChildren > 0 ? remainingSpace / totalChildren : 0.0;
leadingSpace = betweenSpace / 2.0;
break;
case MainAxisAlignment.spaceEvenly:
betweenSpace =
totalChildren > 0 ? remainingSpace / (totalChildren + 1) : 0.0;
leadingSpace = betweenSpace;
break;
}
// Position elements
final flipCrossAxis = (verticalDirection == VerticalDirection.down &&
direction == Axis.horizontal) ||
(verticalDirection == VerticalDirection.up &&
direction == Axis.vertical);
var childMainPosition =
flipMainAxis ? actualSize - leadingSpace : leadingSpace;
for (var child
in children.sublist(_context.firstChild, _context.lastChild)) {
double? childCrossPosition;
switch (crossAxisAlignment) {
case CrossAxisAlignment.start:
childCrossPosition =
flipCrossAxis ? crossSize - _getCrossSize(child) : 0.0;
break;
case CrossAxisAlignment.end:
childCrossPosition =
!flipCrossAxis ? crossSize - _getCrossSize(child) : 0.0;
break;
case CrossAxisAlignment.center:
childCrossPosition = crossSize / 2.0 - _getCrossSize(child) / 2.0;
break;
case CrossAxisAlignment.stretch:
childCrossPosition = 0.0;
break;
}
if (flipMainAxis) {
childMainPosition -= _getMainSize(child);
}
switch (direction) {
case Axis.horizontal:
child.box = PdfRect(box!.x + childMainPosition,
box!.y + childCrossPosition, child.box!.width, child.box!.height);
break;
case Axis.vertical:
child.box = PdfRect(childCrossPosition, childMainPosition,
child.box!.width, child.box!.height);
break;
}
if (flipMainAxis) {
childMainPosition -= betweenSpace;
} else {
childMainPosition += _getMainSize(child) + betweenSpace;
}
}
}