constraintGrid function
List<Widget>
constraintGrid({
- required ConstraintId id,
- required ConstraintAlign left,
- required ConstraintAlign top,
- required int itemCount,
- required int columnCount,
- double? itemWidth,
- double? itemHeight,
- double? itemSize,
- Size itemSizeBuilder()?,
- required Widget itemBuilder(),
- EdgeInsets itemMarginBuilder()?,
- int itemSpanBuilder(
- int index
- EdgeInsets margin = EdgeInsets.zero,
- CLVisibility visibility = visible,
- Offset translate = Offset.zero,
- bool translateConstraint = false,
- int? zIndex,
For list、grid、staggered grid
Implementation
List<Widget> constraintGrid({
required ConstraintId id,
required ConstraintAlign left,
required ConstraintAlign top,
required int itemCount,
required int columnCount,
double? itemWidth,
double? itemHeight,
double? itemSize,
Size Function(int index, int rowIndex, int columnIndex)? itemSizeBuilder,
required Widget Function(int index, int rowIndex, int columnIndex)
itemBuilder,
EdgeInsets Function(int index, int rowIndex, int columnIndex)?
itemMarginBuilder,
int Function(int index)? itemSpanBuilder,
EdgeInsets margin = EdgeInsets.zero,
CLVisibility visibility = visible,
Offset translate = Offset.zero,
bool translateConstraint = false,
int? zIndex,
}) {
assert(itemCount > 0);
assert(columnCount > 0);
assert(itemWidth == null || (itemWidth >= 0 || itemWidth != matchConstraint));
assert(
itemHeight == null || (itemHeight >= 0 || itemHeight != matchConstraint));
assert(itemSize == null || (itemSize >= 0 || itemSize != matchConstraint));
if (itemSize != null) {
itemWidth = itemSize;
itemHeight = itemSize;
}
assert((itemSizeBuilder == null && itemWidth != null && itemHeight != null) ||
(itemSizeBuilder != null && itemWidth == null && itemHeight == null));
List<Widget> widgets = [];
ConstraintAlign leftAnchor = left;
ConstraintAlign topAnchor = top;
EdgeInsets leftMargin = EdgeInsets.only(
left: margin.left,
);
EdgeInsets topMargin = EdgeInsets.only(
top: margin.top,
);
List<ConstraintId> allChildIds = [];
List<ConstraintId> leftChildIds = [];
List<ConstraintId> topChildIds = [];
List<ConstraintId> rightChildIds = [];
List<ConstraintId> bottomChildIds = [];
int totalAvailableSpanCount = (itemCount / columnCount).ceil() * columnCount;
int currentRowIndex = -1;
int currentRowUsedSpanCount = columnCount + 1;
int totalUsedSpanCount = 0;
late int currentRowBarrierCount;
List<ConstraintId?> currentSpanSlot = List.filled(columnCount + 1, null);
for (int i = 0; i < itemCount; i++) {
ConstraintId itemId = ConstraintId(id.id + '_grid_item_$i');
allChildIds.add(itemId);
int itemSpan = itemSpanBuilder?.call(i) ?? 1;
assert(itemSpan >= 1 && itemSpan <= columnCount);
currentRowUsedSpanCount += itemSpan;
totalUsedSpanCount += itemSpan;
late EdgeInsets childMargin;
/// New row start
if (currentRowUsedSpanCount > columnCount) {
currentRowIndex++;
currentRowUsedSpanCount = itemSpan;
currentRowBarrierCount = 0;
if (i > 0) {
if (!rightChildIds.contains(allChildIds[i - 1])) {
/// Last column
rightChildIds.add(allChildIds[i - 1]);
}
} else {
if (itemSpan == columnCount) {
/// Last column
rightChildIds.add(itemId);
}
}
/// First column
leftAnchor = left;
leftChildIds.add(itemId);
childMargin = (itemMarginBuilder?.call(
i, currentRowIndex, currentRowUsedSpanCount - 1) ??
EdgeInsets.zero)
.add(leftMargin) as EdgeInsets;
} else {
childMargin = itemMarginBuilder?.call(
i, currentRowIndex, currentRowUsedSpanCount - 1) ??
EdgeInsets.zero;
}
// First row
if (currentRowIndex == 0) {
childMargin = childMargin.add(topMargin) as EdgeInsets;
topChildIds.add(itemId);
}
// Last row
if (totalAvailableSpanCount - totalUsedSpanCount < columnCount) {
bottomChildIds.add(itemId);
}
if (currentRowIndex > 0) {
if (itemSpan == 1) {
topAnchor = currentSpanSlot[currentRowUsedSpanCount]!.bottom;
} else {
List<ConstraintId> referencedIds = [];
for (int i = 0; i < itemSpan; i++) {
ConstraintId id = currentSpanSlot[currentRowUsedSpanCount - i]!;
if (!referencedIds.contains(id)) {
referencedIds.add(id);
}
}
ConstraintId rowBarrierId = ConstraintId(id.id +
'_row_${currentRowIndex}_bottom_barrier_$currentRowBarrierCount');
Barrier rowBottomBarrier = Barrier(
id: rowBarrierId,
direction: BarrierDirection.bottom,
referencedIds: referencedIds,
);
widgets.add(rowBottomBarrier);
topAnchor = rowBarrierId.bottom;
currentRowBarrierCount++;
}
}
Widget widget =
itemBuilder(i, currentRowIndex, currentRowUsedSpanCount - 1);
Size? itemSize =
itemSizeBuilder?.call(i, currentRowIndex, currentRowUsedSpanCount - 1);
double width = itemWidth ?? itemSize!.width;
double height = itemHeight ?? itemSize!.height;
widgets.add(Constrained(
child: widget,
constraint: Constraint(
id: itemId,
width: width,
height: height,
left: width == matchParent ? null : leftAnchor,
top: height == matchParent ? null : topAnchor,
zIndex: zIndex,
translate: translate,
visibility: visibility,
margin: childMargin,
goneMargin: childMargin,
),
));
leftAnchor = itemId.right;
for (int i = 0; i < itemSpan; i++) {
currentSpanSlot[currentRowUsedSpanCount - i] = itemId;
}
}
if (!rightChildIds.contains(allChildIds.last)) {
rightChildIds.add(allChildIds.last);
}
Barrier leftBarrier = Barrier(
id: ConstraintId(id.id + '_left_barrier'),
direction: BarrierDirection.left,
referencedIds: leftChildIds,
);
Barrier topBarrier = Barrier(
id: ConstraintId(id.id + '_top_barrier'),
direction: BarrierDirection.top,
referencedIds: topChildIds,
);
Barrier rightBarrier = Barrier(
id: ConstraintId(id.id + '_right_barrier'),
direction: BarrierDirection.right,
referencedIds: rightChildIds,
);
Barrier bottomBarrier = Barrier(
id: ConstraintId(id.id + '_bottom_barrier'),
direction: BarrierDirection.bottom,
referencedIds: bottomChildIds,
);
widgets.add(leftBarrier);
widgets.add(topBarrier);
widgets.add(rightBarrier);
widgets.add(bottomBarrier);
widgets.add(const SizedBox().applyConstraint(
id: id,
size: matchConstraint,
left: leftBarrier.id.left,
top: topBarrier.id.top,
right: rightBarrier.id.right,
bottom: bottomBarrier.id.bottom,
zIndex: -1,
translate: translate,
translateConstraint: translateConstraint,
visibility: invisible,
));
return widgets;
}