splitRect function
Splits a Rect area into multiple sub-rectangles according to layout constraints.
Implementation
List<Rect> splitRect(
Rect area,
List<Constraint> constraints,
LayoutDirection direction,
) {
final clampedArea = Rect(
area.x,
area.y,
max(0, area.width),
max(0, area.height),
);
final totalSize = direction == LayoutDirection.horizontal
? clampedArea.width
: clampedArea.height;
final sizes = List<int>.filled(constraints.length, 0);
var usedSize = 0;
var totalFlex = 0;
final flexIndices = <int>[];
// 1. Calculate fixed sizes, percentages, and min constraints
for (var i = 0; i < constraints.length; i++) {
final c = constraints[i];
if (c is LengthConstraint) {
sizes[i] = c.length;
usedSize += c.length;
} else if (c is PercentageConstraint) {
final size = (totalSize * c.percentage / 100).round();
sizes[i] = size;
usedSize += size;
} else if (c is FlexConstraint) {
totalFlex += c.flex;
flexIndices.add(i);
} else if (c is MinMaxConstraint) {
sizes[i] = c.min;
usedSize += c.min;
}
}
// 2. Distribute remaining space among Flex constraints
if (totalFlex > 0 && usedSize < totalSize) {
final remaining = totalSize - usedSize;
var distributed = 0;
for (var j = 0; j < flexIndices.length; j++) {
final idx = flexIndices[j];
final flex = (constraints[idx] as FlexConstraint).flex;
final size = j == flexIndices.length - 1
? remaining - distributed
: (remaining * flex / totalFlex).floor();
sizes[idx] = size;
distributed += size;
}
usedSize += distributed;
}
// 3. Scale down if used size exceeds total size
if (usedSize > totalSize) {
var currentSum = 0;
for (var i = 0; i < sizes.length; i++) {
sizes[i] = (sizes[i] * totalSize / usedSize).floor();
currentSum += sizes[i];
}
if (currentSum < totalSize) {
for (var i = sizes.length - 1; i >= 0; i--) {
if (sizes[i] > 0) {
sizes[i] += (totalSize - currentSum);
break;
}
}
}
}
// 4. Respect Max Constraints on MinMax
for (var i = 0; i < constraints.length; i++) {
final c = constraints[i];
if (c is MinMaxConstraint) {
sizes[i] = sizes[i].clamp(c.min, c.max);
}
sizes[i] = max(0, sizes[i]);
}
// 5. Construct child Rects
final rects = <Rect>[];
var offset = 0;
for (var i = 0; i < sizes.length; i++) {
final size = sizes[i];
if (direction == LayoutDirection.horizontal) {
rects.add(
Rect(clampedArea.x + offset, clampedArea.y, size, clampedArea.height),
);
} else {
rects.add(
Rect(clampedArea.x, clampedArea.y + offset, clampedArea.width, size),
);
}
offset += size;
}
return rects;
}