@@ -2,6 +2,13 @@ import 'package:flutter/gestures.dart';
22import 'package:flutter/rendering.dart' ;
33import 'package:flutter/widgets.dart' ;
44
5+ /// A GridView with responsive capabilities.
6+ ///
7+ /// ResponsiveGridView extends [GridView] with
8+ /// a custom [ResponsiveGridDelegate] [gridDelegate]
9+ /// that enables greater item size control.
10+ /// Additional parameters [alignment] and [maxRowCount]
11+ /// add grid item positioning capabilities.
512class ResponsiveGridView extends StatelessWidget {
613 final Axis scrollDirection;
714 final bool reverse;
@@ -10,7 +17,11 @@ class ResponsiveGridView extends StatelessWidget {
1017 final ScrollPhysics physics;
1118 final bool shrinkWrap;
1219 final EdgeInsetsGeometry padding;
20+
21+ /// Align grid items together as a group.
1322 final AlignmentGeometry alignment;
23+
24+ /// A custom [SliverGridDelegate] with item size control.
1425 final ResponsiveGridDelegate gridDelegate;
1526 final IndexedWidgetBuilder itemBuilder;
1627 final int itemCount;
@@ -48,22 +59,31 @@ class ResponsiveGridView extends StatelessWidget {
4859
4960 @override
5061 Widget build (BuildContext context) {
62+ // LayoutBuilder provides constraints required for item sizing calculation.
5163 return LayoutBuilder (builder: (context, constraints) {
64+ // The maximum number of items that can fit on one row.
5265 int crossAxisCount;
66+ // The maximum number of items that fit under the max row count.
5367 int maxItemCount;
68+ // Manual padding adjustment for alignment.
5469 EdgeInsetsGeometry alignmentPadding;
70+ // The width of all items and padding.
5571 double crossAxisWidth;
72+ // The maximum width available for items.
5673 double crossAxisExtent = constraints.maxWidth - padding.horizontal;
5774 assert (crossAxisExtent > 0 ,
5875 '$padding exceeds layout width (${constraints .maxWidth })' );
76+ // Switch between grid delegate behavior.
5977 if (gridDelegate.crossAxisExtent != null ) {
78+ // Fixed item size.
6079 crossAxisCount = (crossAxisExtent /
6180 (gridDelegate.crossAxisExtent + gridDelegate.crossAxisSpacing))
6281 .floor ();
6382 crossAxisWidth = crossAxisCount *
6483 (gridDelegate.crossAxisExtent + gridDelegate.crossAxisSpacing) +
6584 padding.horizontal;
6685 } else if (gridDelegate.maxCrossAxisExtent != null ) {
86+ // Max item size.
6787 crossAxisCount = (crossAxisExtent /
6888 (gridDelegate.maxCrossAxisExtent +
6989 gridDelegate.crossAxisSpacing))
@@ -76,6 +96,7 @@ class ResponsiveGridView extends StatelessWidget {
7696 (childCrossAxisExtent + gridDelegate.crossAxisSpacing) +
7797 padding.horizontal;
7898 } else {
99+ // Min item size.
79100 crossAxisCount = (crossAxisExtent /
80101 (gridDelegate.minCrossAxisExtent +
81102 gridDelegate.crossAxisSpacing))
@@ -88,33 +109,46 @@ class ResponsiveGridView extends StatelessWidget {
88109 (childCrossAxisExtent + gridDelegate.crossAxisSpacing) +
89110 padding.horizontal;
90111 }
112+ // Calculate padding adjustment for alignment.
91113 if (alignment == Alignment .centerLeft ||
92114 alignment == Alignment .topLeft ||
93115 alignment == Alignment .bottomLeft) {
116+ // Align left, no padding.
94117 alignmentPadding = EdgeInsets .only (left: 0 );
95118 } else if (alignment == Alignment .center ||
96119 alignment == Alignment .topCenter ||
97120 alignment == Alignment .bottomCenter) {
121+ // Align center, divide remaining space between left and right
122+ // after subtracting last item spacing padding.
98123 double paddingCalc = constraints.maxWidth - crossAxisWidth;
99124 if (paddingCalc <= 0 ) {
125+ // There is no additional space. No padding.
100126 alignmentPadding = EdgeInsets .only (left: 0 );
101127 } else if (paddingCalc > gridDelegate.crossAxisSpacing) {
128+ // There is enough room to center items correctly.
129+ // Add padding equivalent to the last item to the first item.
130+ // Then split the remaining space.
102131 alignmentPadding = EdgeInsets .only (
103132 left: ((constraints.maxWidth -
104133 crossAxisWidth -
105134 gridDelegate.crossAxisSpacing) /
106135 2 ) +
107136 gridDelegate.crossAxisSpacing);
108137 } else {
138+ // There is not enough space to correctly center items.
139+ // Add all remaining space to left padding.
109140 alignmentPadding = EdgeInsets .only (left: paddingCalc);
110141 }
111142 } else {
143+ // Align right, add all remaining space to left padding.
112144 alignmentPadding =
113145 EdgeInsets .only (left: constraints.maxWidth - crossAxisWidth);
114146 }
147+ // Force row limit by calculating item limit.
115148 if (maxRowCount != null ) {
116149 maxItemCount = maxRowCount * crossAxisCount;
117150 }
151+ // Internal children builder delegate.
118152 SliverChildDelegate childrenDelegate = SliverChildBuilderDelegate (
119153 itemBuilder,
120154 childCount: maxItemCount ?? itemCount,
@@ -133,12 +167,7 @@ class ResponsiveGridView extends StatelessWidget {
133167 padding: padding,
134168 gridDelegate: gridDelegate,
135169 childrenDelegate: childrenDelegate,
136- itemBuilder: itemBuilder,
137170 itemCount: itemCount,
138- maxRowCount: maxRowCount,
139- addAutomaticKeepAlives: addAutomaticKeepAlives,
140- addRepaintBoundaries: addRepaintBoundaries,
141- addSemanticIndexes: addSemanticIndexes,
142171 cacheExtent: cacheExtent,
143172 semanticChildCount: semanticChildCount,
144173 dragStartBehavior: dragStartBehavior,
@@ -149,15 +178,11 @@ class ResponsiveGridView extends StatelessWidget {
149178 }
150179}
151180
181+ /// Internal [SliverGridLayout] implementation.
152182class _ResponsiveGridViewLayout extends BoxScrollView {
153183 final ResponsiveGridDelegate gridDelegate;
154184 final SliverChildDelegate childrenDelegate;
155- final IndexedWidgetBuilder itemBuilder;
156185 final int itemCount;
157- final int maxRowCount;
158- final bool addAutomaticKeepAlives;
159- final bool addRepaintBoundaries;
160- final bool addSemanticIndexes;
161186
162187 _ResponsiveGridViewLayout ({
163188 Key key,
@@ -170,12 +195,7 @@ class _ResponsiveGridViewLayout extends BoxScrollView {
170195 EdgeInsetsGeometry padding,
171196 @required this .gridDelegate,
172197 @required this .childrenDelegate,
173- @required this .itemBuilder,
174198 this .itemCount,
175- this .maxRowCount,
176- this .addAutomaticKeepAlives = true ,
177- this .addRepaintBoundaries = true ,
178- this .addSemanticIndexes = true ,
179199 double cacheExtent,
180200 int semanticChildCount,
181201 DragStartBehavior dragStartBehavior = DragStartBehavior .start,
@@ -206,6 +226,12 @@ class _ResponsiveGridViewLayout extends BoxScrollView {
206226 }
207227}
208228
229+ /// A [SliverGridDelegate] with item sizing control.
230+ ///
231+ /// Set a fixed item size by setting the [crossAxisExtent] .
232+ /// Set the maximum item size with [maxCrossAxisExtent] .
233+ /// Set the minimum item size with [minCrossAxisExtent] .
234+ /// One and only one cross axis extent is required.
209235class ResponsiveGridDelegate extends SliverGridDelegate {
210236 const ResponsiveGridDelegate ({
211237 this .crossAxisExtent,
@@ -223,8 +249,13 @@ class ResponsiveGridDelegate extends SliverGridDelegate {
223249 assert (crossAxisSpacing != null && crossAxisSpacing >= 0 ),
224250 assert (childAspectRatio != null && childAspectRatio > 0 );
225251
252+ /// Fixed item size.
226253 final double crossAxisExtent;
254+
255+ /// Maximum item size.
227256 final double maxCrossAxisExtent;
257+
258+ /// Minimum item size.
228259 final double minCrossAxisExtent;
229260 final double mainAxisSpacing;
230261 final double crossAxisSpacing;
@@ -241,11 +272,17 @@ class ResponsiveGridDelegate extends SliverGridDelegate {
241272 @override
242273 SliverGridLayout getLayout (SliverConstraints constraints) {
243274 assert (_debugAssertIsValid (constraints.crossAxisExtent));
275+ // The maximum number of items that can fit on one row.
244276 int crossAxisCount;
277+ // Item height with padding.
245278 double mainAxisStride;
279+ // Item width with padding.
246280 double crossAxisStride;
281+ // Item height.
247282 double childMainAxisExtent;
283+ // Item width.
248284 double childCrossAxisExtent;
285+ // Switch between item sizing behaviors.
249286 if (this .crossAxisExtent != null ) {
250287 crossAxisCount =
251288 (constraints.crossAxisExtent / (crossAxisExtent + crossAxisSpacing))
0 commit comments