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