splitRect function
List<Rect>
splitRect(
- Rect area,
- List<
Constraint> constraints, - LayoutDirection direction, {
- MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
A Viewport wraps a parent buffer, translating and clipping drawing operations
to a relative local coordinate space within bounds.
Implementation
List<Rect> splitRect(
Rect area,
List<Constraint> constraints,
LayoutDirection direction, {
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
}) {
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>[];
final N = sizes.length;
final remaining = totalSize - usedSize;
if (remaining <= 0 || N == 0) {
var offset = 0;
for (var i = 0; i < N; 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;
}
} else {
// We have remaining space to distribute
final sumOfSizes = List<int>.filled(N + 1, 0);
for (var i = 0; i < N; i++) {
sumOfSizes[i + 1] = sumOfSizes[i] + sizes[i];
}
int getChildOffset(int i) => switch (mainAxisAlignment) {
MainAxisAlignment.start => sumOfSizes[i],
MainAxisAlignment.end => remaining + sumOfSizes[i],
MainAxisAlignment.center => (remaining ~/ 2) + sumOfSizes[i],
MainAxisAlignment.spaceBetween =>
N <= 1 ? sumOfSizes[i] : ((remaining * i) ~/ (N - 1)) + sumOfSizes[i],
MainAxisAlignment.spaceAround =>
(remaining * (i * 2 + 1) / (N * 2)).floor() + sumOfSizes[i],
MainAxisAlignment.spaceEvenly =>
(remaining * (i + 1) / (N + 1)).floor() + sumOfSizes[i],
};
for (var i = 0; i < N; i++) {
final size = sizes[i];
final offset = getChildOffset(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),
);
}
}
}
return rects;
}