computeTableSize method
TableLayoutResult
computeTableSize(
- BoxConstraints constraints, [
- IntrinsicComputer? intrinsicComputer
Implementation
TableLayoutResult computeTableSize(BoxConstraints constraints,
[IntrinsicComputer? intrinsicComputer]) {
double flexWidth = 0;
double flexHeight = 0;
double fixedWidth = 0;
double fixedHeight = 0;
Map<int, double> columnWidths = {};
Map<int, double> rowHeights = {};
int maxRow = 0;
int maxColumn = 0;
bool hasTightFlexWidth = false;
bool hasTightFlexHeight = false;
// find the maximum row and column
RenderBox? child = firstChild;
while (child != null) {
final parentData = child.parentData as TableParentData;
if (parentData.computeSize) {
int? column = parentData.column;
int? row = parentData.row;
if (column != null && row != null) {
int columnSpan = parentData.columnSpan ?? 1;
int rowSpan = parentData.rowSpan ?? 1;
maxColumn = max(maxColumn, column + columnSpan - 1);
maxRow = max(maxRow, row + rowSpan - 1);
}
}
child = childAfter(child);
}
// micro-optimization: avoid calculating flexes if there are no flexes
bool hasFlexWidth = false;
bool hasFlexHeight = false;
// row
for (int r = 0; r <= maxRow; r++) {
final heightConstraint = _height(r);
if (heightConstraint is FlexTableSize &&
constraints.hasBoundedHeight &&
intrinsicComputer == null) {
flexHeight += heightConstraint.flex;
hasFlexHeight = true;
if (heightConstraint.fit == FlexFit.tight) {
hasTightFlexHeight = true;
}
} else if (heightConstraint is FixedTableSize) {
fixedHeight += heightConstraint.value;
rowHeights[r] = max(rowHeights[r] ?? 0, heightConstraint.value);
}
}
// column
for (int c = 0; c <= maxColumn; c++) {
final widthConstraint = _width(c);
if (widthConstraint is FlexTableSize && constraints.hasBoundedWidth) {
flexWidth += widthConstraint.flex;
hasFlexWidth = true;
if (widthConstraint.fit == FlexFit.tight) {
hasTightFlexWidth = true;
}
} else if (widthConstraint is FixedTableSize) {
fixedWidth += widthConstraint.value;
columnWidths[c] = max(columnWidths[c] ?? 0, widthConstraint.value);
}
}
double spacePerFlexWidth = 0;
double spacePerFlexHeight = 0;
double remainingWidth;
double remainingHeight;
if (constraints.hasBoundedWidth) {
remainingWidth = constraints.maxWidth - fixedWidth;
} else {
remainingWidth = double.infinity;
}
if (constraints.hasBoundedHeight) {
remainingHeight = constraints.maxHeight - fixedHeight;
} else {
remainingHeight = double.infinity;
}
// find the proper intrinsic sizes (if any)
child = lastChild;
while (child != null) {
final parentData = child.parentData as TableParentData;
if (parentData.computeSize) {
int? column = parentData.column;
int? row = parentData.row;
if (column != null && row != null) {
final widthConstraint = _width(column);
final heightConstraint = _height(row);
if (widthConstraint is IntrinsicTableSize ||
(widthConstraint is FlexTableSize && intrinsicComputer != null)) {
var extent = rowHeights[row] ?? remainingHeight;
double maxIntrinsicWidth = intrinsicComputer != null
? intrinsicComputer(child, extent)
: child.getMaxIntrinsicWidth(extent);
maxIntrinsicWidth = min(maxIntrinsicWidth, remainingWidth);
int columnSpan = parentData.columnSpan ?? 1;
// distribute the intrinsic width to all columns
maxIntrinsicWidth = maxIntrinsicWidth / columnSpan;
for (int i = 0; i < columnSpan; i++) {
columnWidths[column + i] =
max(columnWidths[column + i] ?? 0, maxIntrinsicWidth);
}
}
if (heightConstraint is IntrinsicTableSize ||
(heightConstraint is FlexTableSize &&
intrinsicComputer != null)) {
var extent = columnWidths[column] ?? remainingWidth;
double maxIntrinsicHeight = intrinsicComputer != null
? intrinsicComputer(child, extent)
: child.getMaxIntrinsicHeight(extent);
maxIntrinsicHeight = min(maxIntrinsicHeight, remainingHeight);
int rowSpan = parentData.rowSpan ?? 1;
// distribute the intrinsic height to all rows
maxIntrinsicHeight = maxIntrinsicHeight / rowSpan;
for (int i = 0; i < rowSpan; i++) {
rowHeights[row + i] =
max(columnWidths[row + i] ?? 0, maxIntrinsicHeight);
}
}
}
}
child = childBefore(child);
}
double usedColumnWidth = columnWidths.values.fold(0, (a, b) => a + b);
double usedRowHeight = rowHeights.values.fold(0, (a, b) => a + b);
double looseRemainingWidth = remainingWidth;
double looseRemainingHeight = remainingHeight;
double looseSpacePerFlexWidth = 0;
double looseSpacePerFlexHeight = 0;
if (intrinsicComputer == null) {
// recalculate remaining space for flexes
if (constraints.hasBoundedWidth) {
remainingWidth = constraints.maxWidth - usedColumnWidth;
} else {
remainingWidth = double.infinity;
}
if (constraints.hasInfiniteWidth) {
looseRemainingWidth = double.infinity;
} else {
looseRemainingWidth = max(0, constraints.minWidth - usedColumnWidth);
}
if (constraints.hasBoundedHeight) {
remainingHeight = constraints.maxHeight - usedRowHeight;
} else {
remainingHeight = double.infinity;
}
if (constraints.hasInfiniteHeight) {
looseRemainingHeight = double.infinity;
} else {
looseRemainingHeight = max(0, constraints.minHeight - usedRowHeight);
}
if (flexWidth > 0 && remainingWidth > 0) {
spacePerFlexWidth = remainingWidth / flexWidth;
} else {
spacePerFlexWidth = 0;
}
if (flexWidth > 0 && looseRemainingWidth > 0) {
looseSpacePerFlexWidth = looseRemainingWidth / flexWidth;
}
if (flexHeight > 0 && remainingHeight > 0) {
spacePerFlexHeight = remainingHeight / flexHeight;
} else {
spacePerFlexHeight = 0;
}
if (flexHeight > 0 && looseRemainingHeight > 0) {
spacePerFlexHeight = looseRemainingHeight / flexHeight;
}
// calculate space used for flexes
if (hasFlexWidth) {
for (int c = 0; c <= maxColumn; c++) {
final widthConstraint = _width(c);
if (widthConstraint is FlexTableSize) {
// columnWidths[c] = widthConstraint.flex * spacePerFlexWidth;
if (widthConstraint.fit == FlexFit.tight || hasTightFlexWidth) {
columnWidths[c] = widthConstraint.flex * spacePerFlexWidth;
} else {
columnWidths[c] = widthConstraint.flex * looseSpacePerFlexWidth;
}
}
}
}
if (hasFlexHeight) {
for (int r = 0; r <= maxRow; r++) {
final heightConstraint = _height(r);
if (heightConstraint is FlexTableSize) {
// rowHeights[r] = heightConstraint.flex * spacePerFlexHeight;
if (heightConstraint.fit == FlexFit.tight || hasTightFlexHeight) {
rowHeights[r] = heightConstraint.flex * spacePerFlexHeight;
} else {
rowHeights[r] = heightConstraint.flex * looseSpacePerFlexHeight;
}
}
}
}
}
// convert the column widths and row heights to a list, where missing values are 0
List<double> columnWidthsList = List.generate(maxColumn + 1, (index) {
return columnWidths[index] ?? 0;
});
columnWidths.forEach((key, value) {
columnWidthsList[key] = value;
});
List<double> rowHeightsList =
// List.filled(rowHeights.keys.reduce(max) + 1, 0);
List.generate(maxRow + 1, (index) {
return rowHeights[index] ?? 0;
});
rowHeights.forEach((key, value) {
rowHeightsList[key] = value;
});
return TableLayoutResult(
columnWidths: columnWidthsList,
rowHeights: rowHeightsList,
remainingWidth: remainingWidth,
remainingHeight: remainingHeight,
remainingLooseWidth: looseRemainingWidth,
remainingLooseHeight: looseRemainingHeight,
hasTightFlexWidth: hasTightFlexWidth,
hasTightFlexHeight: hasTightFlexHeight,
);
}