Showing
2 changed files
with
128 additions
and
30 deletions
| @@ -3,6 +3,7 @@ | @@ -3,6 +3,7 @@ | ||
| 3 | * Add Document properties | 3 | * Add Document properties |
| 4 | * Add Page.orientation to force landscape or portrait | 4 | * Add Page.orientation to force landscape or portrait |
| 5 | * Improve MultiPage Widget | 5 | * Improve MultiPage Widget |
| 6 | +* Convert GridView to a SpanningWidget | ||
| 6 | 7 | ||
| 7 | # 1.3.3 | 8 | # 1.3.3 |
| 8 | * Fix a bug with the RichText Widget | 9 | * Fix a bug with the RichText Widget |
| @@ -16,7 +16,19 @@ | @@ -16,7 +16,19 @@ | ||
| 16 | 16 | ||
| 17 | part of widget; | 17 | part of widget; |
| 18 | 18 | ||
| 19 | -class GridView extends MultiChildWidget { | 19 | +class _GridViewContext extends WidgetContext { |
| 20 | + int firstChild = 0; | ||
| 21 | + int lastChild = 0; | ||
| 22 | + | ||
| 23 | + double childCrossAxis; | ||
| 24 | + double childMainAxis; | ||
| 25 | + | ||
| 26 | + @override | ||
| 27 | + String toString() => | ||
| 28 | + 'GridViewContext first:$firstChild last:$lastChild size:${childCrossAxis}x$childMainAxis'; | ||
| 29 | +} | ||
| 30 | + | ||
| 31 | +class GridView extends MultiChildWidget implements SpanningWidget { | ||
| 20 | GridView( | 32 | GridView( |
| 21 | {this.direction = Axis.vertical, | 33 | {this.direction = Axis.vertical, |
| 22 | this.padding = EdgeInsets.zero, | 34 | this.padding = EdgeInsets.zero, |
| @@ -35,15 +47,22 @@ class GridView extends MultiChildWidget { | @@ -35,15 +47,22 @@ class GridView extends MultiChildWidget { | ||
| 35 | final double crossAxisSpacing; | 47 | final double crossAxisSpacing; |
| 36 | final double childAspectRatio; | 48 | final double childAspectRatio; |
| 37 | 49 | ||
| 38 | - double _childCrossAxis; | ||
| 39 | - double _childMainAxis; | ||
| 40 | - double _totalMain; | ||
| 41 | - double _totalCross; | 50 | + final _GridViewContext _context = _GridViewContext(); |
| 51 | + | ||
| 42 | int _mainAxisCount; | 52 | int _mainAxisCount; |
| 43 | 53 | ||
| 44 | @override | 54 | @override |
| 45 | void layout(Context context, BoxConstraints constraints, | 55 | void layout(Context context, BoxConstraints constraints, |
| 46 | {bool parentUsesSize = false}) { | 56 | {bool parentUsesSize = false}) { |
| 57 | + assert(() { | ||
| 58 | + if (constraints.maxHeight.isInfinite && childAspectRatio.isInfinite) { | ||
| 59 | + print( | ||
| 60 | + 'Unable to calculate the GridView dimensions. Please set one the height constraints or childAspectRatio.'); | ||
| 61 | + return false; | ||
| 62 | + } | ||
| 63 | + return true; | ||
| 64 | + }()); | ||
| 65 | + | ||
| 47 | double mainAxisExtent; | 66 | double mainAxisExtent; |
| 48 | double crossAxisExtent; | 67 | double crossAxisExtent; |
| 49 | switch (direction) { | 68 | switch (direction) { |
| @@ -57,16 +76,38 @@ class GridView extends MultiChildWidget { | @@ -57,16 +76,38 @@ class GridView extends MultiChildWidget { | ||
| 57 | break; | 76 | break; |
| 58 | } | 77 | } |
| 59 | 78 | ||
| 60 | - _mainAxisCount = (children.length / crossAxisCount).ceil(); | ||
| 61 | - _childCrossAxis = crossAxisExtent / crossAxisCount - | 79 | + if (constraints.maxHeight.isInfinite || _mainAxisCount == null) { |
| 80 | + _mainAxisCount = | ||
| 81 | + ((children.length - _context.firstChild) / crossAxisCount).ceil(); | ||
| 82 | + | ||
| 83 | + _context.childCrossAxis = crossAxisExtent / crossAxisCount - | ||
| 62 | (crossAxisSpacing * (crossAxisCount - 1) / crossAxisCount); | 84 | (crossAxisSpacing * (crossAxisCount - 1) / crossAxisCount); |
| 63 | - _childMainAxis = math.min( | ||
| 64 | - _childCrossAxis * childAspectRatio, | 85 | + |
| 86 | + _context.childMainAxis = math.min( | ||
| 87 | + _context.childCrossAxis * childAspectRatio, | ||
| 65 | mainAxisExtent / _mainAxisCount - | 88 | mainAxisExtent / _mainAxisCount - |
| 66 | (mainAxisSpacing * (_mainAxisCount - 1) / _mainAxisCount)); | 89 | (mainAxisSpacing * (_mainAxisCount - 1) / _mainAxisCount)); |
| 67 | - _totalMain = | ||
| 68 | - (_childMainAxis + mainAxisSpacing) * _mainAxisCount - mainAxisSpacing; | ||
| 69 | - _totalCross = (_childCrossAxis + crossAxisSpacing) * crossAxisCount - | 90 | + |
| 91 | + if (_context.childCrossAxis.isInfinite) { | ||
| 92 | + throw Exception( | ||
| 93 | + 'Unable to calculate child height as the height constraint is infinite.'); | ||
| 94 | + } | ||
| 95 | + } else { | ||
| 96 | + _mainAxisCount = ((mainAxisExtent + mainAxisSpacing) / | ||
| 97 | + (mainAxisSpacing + _context.childMainAxis)) | ||
| 98 | + .floor(); | ||
| 99 | + | ||
| 100 | + if (_mainAxisCount < 0) { | ||
| 101 | + // Not enough space to put one line, try to ask for more space. | ||
| 102 | + _mainAxisCount = 0; | ||
| 103 | + } | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + final double totalMain = | ||
| 107 | + (_context.childMainAxis + mainAxisSpacing) * _mainAxisCount - | ||
| 108 | + mainAxisSpacing; | ||
| 109 | + final double totalCross = | ||
| 110 | + (_context.childCrossAxis + crossAxisSpacing) * crossAxisCount - | ||
| 70 | crossAxisSpacing; | 111 | crossAxisSpacing; |
| 71 | 112 | ||
| 72 | final double startX = padding.left; | 113 | final double startX = padding.left; |
| @@ -77,30 +118,35 @@ class GridView extends MultiChildWidget { | @@ -77,30 +118,35 @@ class GridView extends MultiChildWidget { | ||
| 77 | switch (direction) { | 118 | switch (direction) { |
| 78 | case Axis.vertical: | 119 | case Axis.vertical: |
| 79 | innerConstraints = BoxConstraints.tightFor( | 120 | innerConstraints = BoxConstraints.tightFor( |
| 80 | - width: _childCrossAxis, height: _childMainAxis); | 121 | + width: _context.childCrossAxis, height: _context.childMainAxis); |
| 81 | crossAxis = startX; | 122 | crossAxis = startX; |
| 82 | mainAxis = startY; | 123 | mainAxis = startY; |
| 83 | break; | 124 | break; |
| 84 | case Axis.horizontal: | 125 | case Axis.horizontal: |
| 85 | innerConstraints = BoxConstraints.tightFor( | 126 | innerConstraints = BoxConstraints.tightFor( |
| 86 | - width: _childMainAxis, height: _childCrossAxis); | 127 | + width: _context.childMainAxis, height: _context.childCrossAxis); |
| 87 | mainAxis = startX; | 128 | mainAxis = startX; |
| 88 | crossAxis = startY; | 129 | crossAxis = startY; |
| 89 | break; | 130 | break; |
| 90 | } | 131 | } |
| 91 | 132 | ||
| 92 | int c = 0; | 133 | int c = 0; |
| 93 | - for (Widget child in children) { | 134 | + _context.lastChild = _context.firstChild; |
| 135 | + | ||
| 136 | + for (Widget child in children.sublist( | ||
| 137 | + _context.firstChild, | ||
| 138 | + math.min(children.length, | ||
| 139 | + _context.firstChild + crossAxisCount * _mainAxisCount))) { | ||
| 94 | child.layout(context, innerConstraints); | 140 | child.layout(context, innerConstraints); |
| 95 | 141 | ||
| 96 | switch (direction) { | 142 | switch (direction) { |
| 97 | case Axis.vertical: | 143 | case Axis.vertical: |
| 98 | child.box = PdfRect.fromPoints( | 144 | child.box = PdfRect.fromPoints( |
| 99 | PdfPoint( | 145 | PdfPoint( |
| 100 | - (_childCrossAxis - child.box.width) / 2.0 + crossAxis, | ||
| 101 | - _totalMain + | 146 | + (_context.childCrossAxis - child.box.width) / 2.0 + crossAxis, |
| 147 | + totalMain + | ||
| 102 | padding.bottom - | 148 | padding.bottom - |
| 103 | - (_childMainAxis - child.box.height) / 2.0 - | 149 | + (_context.childMainAxis - child.box.height) / 2.0 - |
| 104 | mainAxis - | 150 | mainAxis - |
| 105 | child.box.height), | 151 | child.box.height), |
| 106 | child.box.size); | 152 | child.box.size); |
| @@ -108,10 +154,10 @@ class GridView extends MultiChildWidget { | @@ -108,10 +154,10 @@ class GridView extends MultiChildWidget { | ||
| 108 | case Axis.horizontal: | 154 | case Axis.horizontal: |
| 109 | child.box = PdfRect.fromPoints( | 155 | child.box = PdfRect.fromPoints( |
| 110 | PdfPoint( | 156 | PdfPoint( |
| 111 | - (_childMainAxis - child.box.width) / 2.0 + mainAxis, | ||
| 112 | - _totalCross + | 157 | + (_context.childMainAxis - child.box.width) / 2.0 + mainAxis, |
| 158 | + totalCross + | ||
| 113 | padding.bottom - | 159 | padding.bottom - |
| 114 | - (_childCrossAxis - child.box.height) / 2.0 - | 160 | + (_context.childCrossAxis - child.box.height) / 2.0 - |
| 115 | crossAxis - | 161 | crossAxis - |
| 116 | child.box.height), | 162 | child.box.height), |
| 117 | child.box.size); | 163 | child.box.size); |
| @@ -119,24 +165,38 @@ class GridView extends MultiChildWidget { | @@ -119,24 +165,38 @@ class GridView extends MultiChildWidget { | ||
| 119 | } | 165 | } |
| 120 | 166 | ||
| 121 | if (++c >= crossAxisCount) { | 167 | if (++c >= crossAxisCount) { |
| 122 | - mainAxis += _childMainAxis + mainAxisSpacing; | 168 | + mainAxis += _context.childMainAxis + mainAxisSpacing; |
| 169 | + switch (direction) { | ||
| 170 | + case Axis.vertical: | ||
| 123 | crossAxis = startX; | 171 | crossAxis = startX; |
| 172 | + break; | ||
| 173 | + case Axis.horizontal: | ||
| 174 | + crossAxis = startY; | ||
| 175 | + break; | ||
| 176 | + } | ||
| 124 | c = 0; | 177 | c = 0; |
| 178 | + | ||
| 179 | + if (mainAxis > mainAxisExtent) { | ||
| 180 | + _context.lastChild++; | ||
| 181 | + | ||
| 182 | + break; | ||
| 183 | + } | ||
| 125 | } else { | 184 | } else { |
| 126 | - crossAxis += _childCrossAxis + crossAxisSpacing; | 185 | + crossAxis += _context.childCrossAxis + crossAxisSpacing; |
| 127 | } | 186 | } |
| 187 | + _context.lastChild++; | ||
| 128 | } | 188 | } |
| 129 | 189 | ||
| 130 | switch (direction) { | 190 | switch (direction) { |
| 131 | case Axis.vertical: | 191 | case Axis.vertical: |
| 132 | box = constraints.constrainRect( | 192 | box = constraints.constrainRect( |
| 133 | - width: _totalCross + padding.horizontal, | ||
| 134 | - height: _totalMain + padding.vertical); | 193 | + width: totalCross + padding.horizontal, |
| 194 | + height: totalMain + padding.vertical); | ||
| 135 | break; | 195 | break; |
| 136 | case Axis.horizontal: | 196 | case Axis.horizontal: |
| 137 | box = constraints.constrainRect( | 197 | box = constraints.constrainRect( |
| 138 | - width: _totalMain + padding.horizontal, | ||
| 139 | - height: _totalCross + padding.vertical); | 198 | + width: totalMain + padding.horizontal, |
| 199 | + height: totalCross + padding.vertical); | ||
| 140 | break; | 200 | break; |
| 141 | } | 201 | } |
| 142 | } | 202 | } |
| @@ -164,7 +224,7 @@ class GridView extends MultiChildWidget { | @@ -164,7 +224,7 @@ class GridView extends MultiChildWidget { | ||
| 164 | ..drawRect( | 224 | ..drawRect( |
| 165 | box.left + | 225 | box.left + |
| 166 | padding.left + | 226 | padding.left + |
| 167 | - (_childCrossAxis + crossAxisSpacing) * c - | 227 | + (_context.childCrossAxis + crossAxisSpacing) * c - |
| 168 | crossAxisSpacing, | 228 | crossAxisSpacing, |
| 169 | box.bottom + padding.bottom, | 229 | box.bottom + padding.bottom, |
| 170 | math.max(crossAxisSpacing, 1), | 230 | math.max(crossAxisSpacing, 1), |
| @@ -172,6 +232,16 @@ class GridView extends MultiChildWidget { | @@ -172,6 +232,16 @@ class GridView extends MultiChildWidget { | ||
| 172 | ..fillPath(); | 232 | ..fillPath(); |
| 173 | break; | 233 | break; |
| 174 | case Axis.horizontal: | 234 | case Axis.horizontal: |
| 235 | + context.canvas | ||
| 236 | + ..drawRect( | ||
| 237 | + box.left + padding.left, | ||
| 238 | + box.bottom + | ||
| 239 | + padding.bottom + | ||
| 240 | + (_context.childCrossAxis + crossAxisSpacing) * c - | ||
| 241 | + crossAxisSpacing, | ||
| 242 | + box.width - padding.horizontal, | ||
| 243 | + math.max(crossAxisSpacing, 1)) | ||
| 244 | + ..fillPath(); | ||
| 175 | break; | 245 | break; |
| 176 | } | 246 | } |
| 177 | } | 247 | } |
| @@ -184,13 +254,23 @@ class GridView extends MultiChildWidget { | @@ -184,13 +254,23 @@ class GridView extends MultiChildWidget { | ||
| 184 | box.left + padding.left, | 254 | box.left + padding.left, |
| 185 | box.bottom + | 255 | box.bottom + |
| 186 | padding.bottom + | 256 | padding.bottom + |
| 187 | - (_childMainAxis + mainAxisSpacing) * c - | 257 | + (_context.childMainAxis + mainAxisSpacing) * c - |
| 188 | mainAxisSpacing, | 258 | mainAxisSpacing, |
| 189 | box.width - padding.horizontal, | 259 | box.width - padding.horizontal, |
| 190 | math.max(mainAxisSpacing, 1)) | 260 | math.max(mainAxisSpacing, 1)) |
| 191 | ..fillPath(); | 261 | ..fillPath(); |
| 192 | break; | 262 | break; |
| 193 | case Axis.horizontal: | 263 | case Axis.horizontal: |
| 264 | + context.canvas | ||
| 265 | + ..drawRect( | ||
| 266 | + box.left + | ||
| 267 | + padding.left + | ||
| 268 | + (_context.childMainAxis + mainAxisSpacing) * c - | ||
| 269 | + mainAxisSpacing, | ||
| 270 | + box.bottom + padding.bottom, | ||
| 271 | + math.max(mainAxisSpacing, 1), | ||
| 272 | + box.height - padding.vertical) | ||
| 273 | + ..fillPath(); | ||
| 194 | break; | 274 | break; |
| 195 | } | 275 | } |
| 196 | } | 276 | } |
| @@ -205,9 +285,26 @@ class GridView extends MultiChildWidget { | @@ -205,9 +285,26 @@ class GridView extends MultiChildWidget { | ||
| 205 | context.canvas | 285 | context.canvas |
| 206 | ..saveContext() | 286 | ..saveContext() |
| 207 | ..setTransform(mat); | 287 | ..setTransform(mat); |
| 208 | - for (Widget child in children) { | 288 | + |
| 289 | + for (Widget child | ||
| 290 | + in children.sublist(_context.firstChild, _context.lastChild)) { | ||
| 209 | child.paint(context); | 291 | child.paint(context); |
| 210 | } | 292 | } |
| 211 | context.canvas.restoreContext(); | 293 | context.canvas.restoreContext(); |
| 212 | } | 294 | } |
| 295 | + | ||
| 296 | + @override | ||
| 297 | + bool get canSpan => true; | ||
| 298 | + | ||
| 299 | + @override | ||
| 300 | + void restoreContext(WidgetContext context) { | ||
| 301 | + if (context is _GridViewContext) { | ||
| 302 | + _context.firstChild = context.lastChild; | ||
| 303 | + } | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + @override | ||
| 307 | + WidgetContext saveContext() { | ||
| 308 | + return _context; | ||
| 309 | + } | ||
| 213 | } | 310 | } |
-
Please register or login to post a comment