11import 'dart:collection' ;
22import 'dart:convert' ;
3- import 'dart:math' ;
43import 'dart:ui' as ui;
54import 'dart:ui' ;
65
@@ -104,6 +103,7 @@ List<Widget> constraintGrid({
104103 Size Function (int index)? itemSizeBuilder,
105104 required Widget Function (int index) itemBuilder,
106105 EdgeInsets Function (int index)? itemMarginBuilder,
106+ int Function (int index)? itemSpanBuilder,
107107 EdgeInsets margin = EdgeInsets .zero,
108108 CLVisibility visibility = visible,
109109 Offset translate = Offset .zero,
@@ -127,47 +127,91 @@ List<Widget> constraintGrid({
127127 EdgeInsets topMargin = EdgeInsets .only (
128128 top: margin.top,
129129 );
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- }
146130
131+ List <ConstraintId > allChildIds = [];
147132 List <ConstraintId > leftChildIds = [];
148133 List <ConstraintId > topChildIds = [];
149134 List <ConstraintId > rightChildIds = [];
150135 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 ();
153142 for (int i = 0 ; i < itemCount; i++ ) {
154143 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;
156171 leftChildIds.add (itemId);
172+ childMargin = childMargin.add (leftMargin) as EdgeInsets ;
157173 }
158- if (i < columnCount) {
174+
175+ // First row
176+ if (currentRowIndex == 0 ) {
177+ childMargin = childMargin.add (topMargin) as EdgeInsets ;
159178 topChildIds.add (itemId);
160179 }
161- if (i % columnCount == lastColumnIndex) {
162- rightChildIds.add (itemId);
163- }
164- if (i ~ / columnCount == lastRowIndex) {
180+
181+ // Last row
182+ if (totalAvailableSpanCount - totalUsedSpanCount < columnCount) {
165183 bottomChildIds.add (itemId);
166184 }
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+
167210 Widget widget = itemBuilder (i);
168211 Size ? itemSize = itemSizeBuilder? .call (i);
169212 double width = itemWidth ?? itemSize! .width;
170213 double height = itemHeight ?? itemSize! .height;
214+
171215 widgets.add (Constrained (
172216 child: widget,
173217 constraint: Constraint (
@@ -179,17 +223,21 @@ List<Widget> constraintGrid({
179223 zIndex: zIndex,
180224 translate: translate,
181225 visibility: visibility,
182- margin: calculateItemMargin (
183- i, columnCount, itemMarginBuilder ? . call (i) ?? EdgeInsets .zero) ,
226+ margin: childMargin,
227+ goneMargin : childMargin ,
184228 ),
185229 ));
230+
186231 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;
190234 }
191235 }
192236
237+ if (! rightChildIds.contains (allChildIds.last)) {
238+ rightChildIds.add (allChildIds.last);
239+ }
240+
193241 Barrier leftBarrier = Barrier (
194242 id: ConstraintId (id.id + '_left_barrier' ),
195243 direction: BarrierDirection .left,
0 commit comments