Showing
8 changed files
with
87 additions
and
19 deletions
@@ -11,6 +11,7 @@ | @@ -11,6 +11,7 @@ | ||
11 | - Add more font drawing options | 11 | - Add more font drawing options |
12 | - Add Opacity Widget | 12 | - Add Opacity Widget |
13 | - Fix Text height with TrueType fonts | 13 | - Fix Text height with TrueType fonts |
14 | +- Convert Flex to a SpanningWidget | ||
14 | 15 | ||
15 | ## 1.4.1 | 16 | ## 1.4.1 |
16 | 17 |
@@ -56,7 +56,28 @@ enum VerticalDirection { | @@ -56,7 +56,28 @@ enum VerticalDirection { | ||
56 | 56 | ||
57 | typedef _ChildSizingFunction = double Function(Widget child, double extent); | 57 | typedef _ChildSizingFunction = double Function(Widget child, double extent); |
58 | 58 | ||
59 | -class Flex extends MultiChildWidget { | 59 | +class _FlexContext extends WidgetContext { |
60 | + int firstChild = 0; | ||
61 | + int lastChild = 0; | ||
62 | + | ||
63 | + @override | ||
64 | + void apply(WidgetContext other) { | ||
65 | + if (other is _FlexContext) { | ||
66 | + firstChild = other.firstChild; | ||
67 | + lastChild = other.lastChild; | ||
68 | + } | ||
69 | + } | ||
70 | + | ||
71 | + @override | ||
72 | + WidgetContext clone() { | ||
73 | + return _FlexContext()..apply(this); | ||
74 | + } | ||
75 | + | ||
76 | + @override | ||
77 | + String toString() => '$runtimeType first:$firstChild last:$lastChild'; | ||
78 | +} | ||
79 | + | ||
80 | +class Flex extends MultiChildWidget implements SpanningWidget { | ||
60 | Flex({ | 81 | Flex({ |
61 | @required this.direction, | 82 | @required this.direction, |
62 | this.mainAxisAlignment = MainAxisAlignment.start, | 83 | this.mainAxisAlignment = MainAxisAlignment.start, |
@@ -80,6 +101,8 @@ class Flex extends MultiChildWidget { | @@ -80,6 +101,8 @@ class Flex extends MultiChildWidget { | ||
80 | 101 | ||
81 | final VerticalDirection verticalDirection; | 102 | final VerticalDirection verticalDirection; |
82 | 103 | ||
104 | + final _FlexContext _context = _FlexContext(); | ||
105 | + | ||
83 | double _getIntrinsicSize( | 106 | double _getIntrinsicSize( |
84 | {Axis sizingDirection, | 107 | {Axis sizingDirection, |
85 | double | 108 | double |
@@ -209,7 +232,6 @@ class Flex extends MultiChildWidget { | @@ -209,7 +232,6 @@ class Flex extends MultiChildWidget { | ||
209 | {bool parentUsesSize = false}) { | 232 | {bool parentUsesSize = false}) { |
210 | // Determine used flex factor, size inflexible items, calculate free space. | 233 | // Determine used flex factor, size inflexible items, calculate free space. |
211 | int totalFlex = 0; | 234 | int totalFlex = 0; |
212 | - final int totalChildren = children.length; | ||
213 | Widget lastFlexChild; | 235 | Widget lastFlexChild; |
214 | assert(constraints != null); | 236 | assert(constraints != null); |
215 | final double maxMainSize = direction == Axis.horizontal | 237 | final double maxMainSize = direction == Axis.horizontal |
@@ -219,8 +241,9 @@ class Flex extends MultiChildWidget { | @@ -219,8 +241,9 @@ class Flex extends MultiChildWidget { | ||
219 | 241 | ||
220 | double crossSize = 0; | 242 | double crossSize = 0; |
221 | double allocatedSize = 0; // Sum of the sizes of the non-flexible children. | 243 | double allocatedSize = 0; // Sum of the sizes of the non-flexible children. |
244 | + int index = _context.firstChild; | ||
222 | 245 | ||
223 | - for (Widget child in children) { | 246 | + for (Widget child in children.sublist(_context.firstChild)) { |
224 | final int flex = child is Flexible ? child.flex : 0; | 247 | final int flex = child is Flexible ? child.flex : 0; |
225 | final FlexFit fit = child is Flexible ? child.fit : FlexFit.loose; | 248 | final FlexFit fit = child is Flexible ? child.fit : FlexFit.loose; |
226 | if (flex > 0) { | 249 | if (flex > 0) { |
@@ -266,9 +289,16 @@ class Flex extends MultiChildWidget { | @@ -266,9 +289,16 @@ class Flex extends MultiChildWidget { | ||
266 | assert(child.box != null); | 289 | assert(child.box != null); |
267 | allocatedSize += _getMainSize(child); | 290 | allocatedSize += _getMainSize(child); |
268 | crossSize = math.max(crossSize, _getCrossSize(child)); | 291 | crossSize = math.max(crossSize, _getCrossSize(child)); |
292 | + if (direction == Axis.vertical && | ||
293 | + allocatedSize > constraints.maxHeight) { | ||
294 | + break; | ||
295 | + } | ||
269 | } | 296 | } |
270 | lastFlexChild = child; | 297 | lastFlexChild = child; |
298 | + index++; | ||
271 | } | 299 | } |
300 | + _context.lastChild = index; | ||
301 | + final int totalChildren = _context.lastChild - _context.firstChild; | ||
272 | 302 | ||
273 | // Distribute free space to flexible children, and determine baseline. | 303 | // Distribute free space to flexible children, and determine baseline. |
274 | final double freeSpace = | 304 | final double freeSpace = |
@@ -409,7 +439,9 @@ class Flex extends MultiChildWidget { | @@ -409,7 +439,9 @@ class Flex extends MultiChildWidget { | ||
409 | direction == Axis.vertical); | 439 | direction == Axis.vertical); |
410 | double childMainPosition = | 440 | double childMainPosition = |
411 | flipMainAxis ? actualSize - leadingSpace : leadingSpace; | 441 | flipMainAxis ? actualSize - leadingSpace : leadingSpace; |
412 | - for (Widget child in children) { | 442 | + |
443 | + for (Widget child | ||
444 | + in children.sublist(_context.firstChild, _context.lastChild)) { | ||
413 | double childCrossPosition; | 445 | double childCrossPosition; |
414 | switch (crossAxisAlignment) { | 446 | switch (crossAxisAlignment) { |
415 | case CrossAxisAlignment.start: | 447 | case CrossAxisAlignment.start: |
@@ -458,11 +490,31 @@ class Flex extends MultiChildWidget { | @@ -458,11 +490,31 @@ class Flex extends MultiChildWidget { | ||
458 | context.canvas | 490 | context.canvas |
459 | ..saveContext() | 491 | ..saveContext() |
460 | ..setTransform(mat); | 492 | ..setTransform(mat); |
461 | - for (Widget child in children) { | 493 | + |
494 | + for (Widget child | ||
495 | + in children.sublist(_context.firstChild, _context.lastChild)) { | ||
462 | child.paint(context); | 496 | child.paint(context); |
463 | } | 497 | } |
464 | context.canvas.restoreContext(); | 498 | context.canvas.restoreContext(); |
465 | } | 499 | } |
500 | + | ||
501 | + @override | ||
502 | + bool get canSpan => direction == Axis.vertical; | ||
503 | + | ||
504 | + @override | ||
505 | + bool get hasMoreWidgets => true; | ||
506 | + | ||
507 | + @override | ||
508 | + void restoreContext(WidgetContext context) { | ||
509 | + if (context is _FlexContext) { | ||
510 | + _context.firstChild = context.lastChild; | ||
511 | + } | ||
512 | + } | ||
513 | + | ||
514 | + @override | ||
515 | + WidgetContext saveContext() { | ||
516 | + return _context; | ||
517 | + } | ||
466 | } | 518 | } |
467 | 519 | ||
468 | class Row extends Flex { | 520 | class Row extends Flex { |
@@ -328,6 +328,9 @@ class GridView extends MultiChildWidget implements SpanningWidget { | @@ -328,6 +328,9 @@ class GridView extends MultiChildWidget implements SpanningWidget { | ||
328 | bool get canSpan => true; | 328 | bool get canSpan => true; |
329 | 329 | ||
330 | @override | 330 | @override |
331 | + bool get hasMoreWidgets => true; | ||
332 | + | ||
333 | + @override | ||
331 | void restoreContext(WidgetContext context) { | 334 | void restoreContext(WidgetContext context) { |
332 | if (context is _GridViewContext) { | 335 | if (context is _GridViewContext) { |
333 | _context.firstChild = context.lastChild; | 336 | _context.firstChild = context.lastChild; |
@@ -25,7 +25,9 @@ abstract class WidgetContext { | @@ -25,7 +25,9 @@ abstract class WidgetContext { | ||
25 | } | 25 | } |
26 | 26 | ||
27 | abstract class SpanningWidget extends Widget { | 27 | abstract class SpanningWidget extends Widget { |
28 | - bool get canSpan => false; | 28 | + bool get canSpan; |
29 | + | ||
30 | + bool get hasMoreWidgets; | ||
29 | 31 | ||
30 | /// Get unmodified mutable context object | 32 | /// Get unmodified mutable context object |
31 | @protected | 33 | @protected |
@@ -170,6 +172,10 @@ class MultiPage extends Page { | @@ -170,6 +172,10 @@ class MultiPage extends Page { | ||
170 | 172 | ||
171 | while (index < children.length) { | 173 | while (index < children.length) { |
172 | final Widget child = children[index]; | 174 | final Widget child = children[index]; |
175 | + bool canSpan = false; | ||
176 | + if (child is SpanningWidget) { | ||
177 | + canSpan = child.canSpan; | ||
178 | + } | ||
173 | 179 | ||
174 | assert(() { | 180 | assert(() { |
175 | // Detect too big widgets | 181 | // Detect too big widgets |
@@ -226,7 +232,7 @@ class MultiPage extends Page { | @@ -226,7 +232,7 @@ class MultiPage extends Page { | ||
226 | } | 232 | } |
227 | 233 | ||
228 | // If we are processing a multi-page widget, we restore its context | 234 | // If we are processing a multi-page widget, we restore its context |
229 | - if (widgetContext != null && child is SpanningWidget) { | 235 | + if (widgetContext != null && canSpan && child is SpanningWidget) { |
230 | child.restoreContext(widgetContext); | 236 | child.restoreContext(widgetContext); |
231 | widgetContext = null; | 237 | widgetContext = null; |
232 | } | 238 | } |
@@ -238,14 +244,13 @@ class MultiPage extends Page { | @@ -238,14 +244,13 @@ class MultiPage extends Page { | ||
238 | if (offsetStart - child.box.height < offsetEnd) { | 244 | if (offsetStart - child.box.height < offsetEnd) { |
239 | // If it is not a multi-page widget and its height | 245 | // If it is not a multi-page widget and its height |
240 | // is smaller than a full new page, we schedule a new page creation | 246 | // is smaller than a full new page, we schedule a new page creation |
241 | - if (child.box.height <= pageHeight - pageHeightMargin && | ||
242 | - !(child is SpanningWidget)) { | 247 | + if (child.box.height <= pageHeight - pageHeightMargin && !canSpan) { |
243 | context = null; | 248 | context = null; |
244 | continue; | 249 | continue; |
245 | } | 250 | } |
246 | 251 | ||
247 | // Else we crash if the widget is too big and cannot be splitted | 252 | // Else we crash if the widget is too big and cannot be splitted |
248 | - if (!(child is SpanningWidget)) { | 253 | + if (!canSpan) { |
249 | throw Exception( | 254 | throw Exception( |
250 | 'Widget won\'t fit into the page as its height (${child.box.height}) ' | 255 | 'Widget won\'t fit into the page as its height (${child.box.height}) ' |
251 | 'exceed a page height (${pageHeight - pageHeightMargin}). ' | 256 | 'exceed a page height (${pageHeight - pageHeightMargin}). ' |
@@ -270,7 +275,7 @@ class MultiPage extends Page { | @@ -270,7 +275,7 @@ class MultiPage extends Page { | ||
270 | ); | 275 | ); |
271 | 276 | ||
272 | // Has it finished spanning? | 277 | // Has it finished spanning? |
273 | - if (!span.canSpan) { | 278 | + if (!span.hasMoreWidgets) { |
274 | sameCount = 0; | 279 | sameCount = 0; |
275 | index++; | 280 | index++; |
276 | } | 281 | } |
@@ -286,8 +291,9 @@ class MultiPage extends Page { | @@ -286,8 +291,9 @@ class MultiPage extends Page { | ||
286 | x: _margin.left, | 291 | x: _margin.left, |
287 | y: offsetStart - child.box.height, | 292 | y: offsetStart - child.box.height, |
288 | constraints: constraints, | 293 | constraints: constraints, |
289 | - widgetContext: | ||
290 | - child is SpanningWidget ? child.saveContext().clone() : null, | 294 | + widgetContext: child is SpanningWidget && canSpan |
295 | + ? child.saveContext().clone() | ||
296 | + : null, | ||
291 | ), | 297 | ), |
292 | ); | 298 | ); |
293 | 299 | ||
@@ -315,7 +321,7 @@ class MultiPage extends Page { | @@ -315,7 +321,7 @@ class MultiPage extends Page { | ||
315 | 321 | ||
316 | for (_MultiPageWidget widget in page.widgets) { | 322 | for (_MultiPageWidget widget in page.widgets) { |
317 | final Widget child = widget.child; | 323 | final Widget child = widget.child; |
318 | - if (child is SpanningWidget) { | 324 | + if (child is SpanningWidget && child.canSpan) { |
319 | final WidgetContext context = child.saveContext(); | 325 | final WidgetContext context = child.saveContext(); |
320 | context.apply(widget.widgetContext); | 326 | context.apply(widget.widgetContext); |
321 | } | 327 | } |
@@ -224,6 +224,9 @@ class Table extends Widget implements SpanningWidget { | @@ -224,6 +224,9 @@ class Table extends Widget implements SpanningWidget { | ||
224 | @override | 224 | @override |
225 | bool get canSpan => true; | 225 | bool get canSpan => true; |
226 | 226 | ||
227 | + @override | ||
228 | + bool get hasMoreWidgets => true; | ||
229 | + | ||
227 | /// The rows of the table. | 230 | /// The rows of the table. |
228 | final List<TableRow> children; | 231 | final List<TableRow> children; |
229 | 232 |
@@ -109,7 +109,10 @@ class Wrap extends MultiChildWidget implements SpanningWidget { | @@ -109,7 +109,10 @@ class Wrap extends MultiChildWidget implements SpanningWidget { | ||
109 | bool get textDirection => false; | 109 | bool get textDirection => false; |
110 | 110 | ||
111 | @override | 111 | @override |
112 | - bool get canSpan => _context.lastChild < children.length; | 112 | + bool get canSpan => true; |
113 | + | ||
114 | + @override | ||
115 | + bool get hasMoreWidgets => _context.lastChild < children.length; | ||
113 | 116 | ||
114 | final _WrapContext _context = _WrapContext(); | 117 | final _WrapContext _context = _WrapContext(); |
115 | 118 |
No preview for this file type
No preview for this file type
-
Please register or login to post a comment