1
1
import 'dart:collection' ;
2
2
import 'dart:convert' ;
3
- import 'dart:math' ;
4
3
import 'dart:ui' as ui;
5
4
import 'dart:ui' ;
6
5
@@ -104,6 +103,7 @@ List<Widget> constraintGrid({
104
103
Size Function (int index)? itemSizeBuilder,
105
104
required Widget Function (int index) itemBuilder,
106
105
EdgeInsets Function (int index)? itemMarginBuilder,
106
+ int Function (int index)? itemSpanBuilder,
107
107
EdgeInsets margin = EdgeInsets .zero,
108
108
CLVisibility visibility = visible,
109
109
Offset translate = Offset .zero,
@@ -127,47 +127,91 @@ List<Widget> constraintGrid({
127
127
EdgeInsets topMargin = EdgeInsets .only (
128
128
top: margin.top,
129
129
);
130
- EdgeInsets calculateItemMargin (
131
- int index,
132
- int columnCount,
133
- EdgeInsets margin,
134
- ) {
135
- /// First row
136
- if (index < columnCount) {
137
- margin = margin.add (topMargin) as EdgeInsets ;
138
- }
139
-
140
- /// First column
141
- if (index % columnCount == 0 ) {
142
- margin = margin.add (leftMargin) as EdgeInsets ;
143
- }
144
- return margin;
145
- }
146
130
131
+ List <ConstraintId > allChildIds = [];
147
132
List <ConstraintId > leftChildIds = [];
148
133
List <ConstraintId > topChildIds = [];
149
134
List <ConstraintId > rightChildIds = [];
150
135
List <ConstraintId > bottomChildIds = [];
151
- int lastRowIndex = (itemCount / columnCount).ceil () - 1 ;
152
- int lastColumnIndex = min (columnCount - 1 , itemCount - 1 );
136
+ int totalAvailableSpanCount = (itemCount / columnCount).ceil () * columnCount;
137
+ int currentRowIndex = - 1 ;
138
+ int currentRowUsedSpanCount = columnCount + 1 ;
139
+ int totalUsedSpanCount = 0 ;
140
+ late int currentRowBarrierCount;
141
+ Map <int , ConstraintId > currentSpanSlot = HashMap ();
153
142
for (int i = 0 ; i < itemCount; i++ ) {
154
143
ConstraintId itemId = ConstraintId (id.id + '_grid_item_$i ' );
155
- if (i % columnCount == 0 ) {
144
+ allChildIds.add (itemId);
145
+
146
+ EdgeInsets childMargin = itemMarginBuilder? .call (i) ?? EdgeInsets .zero;
147
+ int itemSpan = itemSpanBuilder? .call (i) ?? 1 ;
148
+ assert (itemSpan >= 1 && itemSpan <= columnCount);
149
+ currentRowUsedSpanCount += itemSpan;
150
+ totalUsedSpanCount += itemSpan;
151
+
152
+ /// New row start
153
+ if (currentRowUsedSpanCount > columnCount) {
154
+ currentRowIndex++ ;
155
+ currentRowUsedSpanCount = itemSpan;
156
+ currentRowBarrierCount = 0 ;
157
+ if (i > 0 ) {
158
+ if (! rightChildIds.contains (allChildIds[i - 1 ])) {
159
+ /// Last column
160
+ rightChildIds.add (allChildIds[i - 1 ]);
161
+ }
162
+ } else {
163
+ if (itemSpan == columnCount) {
164
+ /// Last column
165
+ rightChildIds.add (itemId);
166
+ }
167
+ }
168
+
169
+ /// First column
170
+ leftAnchor = left;
156
171
leftChildIds.add (itemId);
172
+ childMargin = childMargin.add (leftMargin) as EdgeInsets ;
157
173
}
158
- if (i < columnCount) {
174
+
175
+ // First row
176
+ if (currentRowIndex == 0 ) {
177
+ childMargin = childMargin.add (topMargin) as EdgeInsets ;
159
178
topChildIds.add (itemId);
160
179
}
161
- if (i % columnCount == lastColumnIndex) {
162
- rightChildIds.add (itemId);
163
- }
164
- if (i ~ / columnCount == lastRowIndex) {
180
+
181
+ // Last row
182
+ if (totalAvailableSpanCount - totalUsedSpanCount < columnCount) {
165
183
bottomChildIds.add (itemId);
166
184
}
185
+
186
+ if (currentRowIndex > 0 ) {
187
+ if (itemSpan == 1 ) {
188
+ topAnchor = currentSpanSlot[currentRowUsedSpanCount]! .bottom;
189
+ } else {
190
+ List <ConstraintId > referencedIds = [];
191
+ for (int i = 0 ; i < itemSpan; i++ ) {
192
+ ConstraintId id = currentSpanSlot[currentRowUsedSpanCount - i]! ;
193
+ if (! referencedIds.contains (id)) {
194
+ referencedIds.add (id);
195
+ }
196
+ }
197
+ ConstraintId rowBarrierId = ConstraintId (id.id +
198
+ '_row_${currentRowIndex }_bottom_barrier_$currentRowBarrierCount ' );
199
+ Barrier rowBottomBarrier = Barrier (
200
+ id: rowBarrierId,
201
+ direction: BarrierDirection .bottom,
202
+ referencedIds: referencedIds,
203
+ );
204
+ widgets.add (rowBottomBarrier);
205
+ topAnchor = rowBarrierId.bottom;
206
+ currentRowBarrierCount++ ;
207
+ }
208
+ }
209
+
167
210
Widget widget = itemBuilder (i);
168
211
Size ? itemSize = itemSizeBuilder? .call (i);
169
212
double width = itemWidth ?? itemSize! .width;
170
213
double height = itemHeight ?? itemSize! .height;
214
+
171
215
widgets.add (Constrained (
172
216
child: widget,
173
217
constraint: Constraint (
@@ -179,17 +223,21 @@ List<Widget> constraintGrid({
179
223
zIndex: zIndex,
180
224
translate: translate,
181
225
visibility: visibility,
182
- margin: calculateItemMargin (
183
- i, columnCount, itemMarginBuilder ? . call (i) ?? EdgeInsets .zero) ,
226
+ margin: childMargin,
227
+ goneMargin : childMargin ,
184
228
),
185
229
));
230
+
186
231
leftAnchor = itemId.right;
187
- if (i % columnCount == columnCount - 1 ) {
188
- leftAnchor = left;
189
- topAnchor = itemId.bottom;
232
+ for (int i = 0 ; i < itemSpan; i++ ) {
233
+ currentSpanSlot[currentRowUsedSpanCount - i] = itemId;
190
234
}
191
235
}
192
236
237
+ if (! rightChildIds.contains (allChildIds.last)) {
238
+ rightChildIds.add (allChildIds.last);
239
+ }
240
+
193
241
Barrier leftBarrier = Barrier (
194
242
id: ConstraintId (id.id + '_left_barrier' ),
195
243
direction: BarrierDirection .left,
0 commit comments