1 | // Copyright 2014 The Flutter Authors. All rights reserved. |
---|---|
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | /// @docImport 'single_child_scroll_view.dart'; |
6 | library; |
7 | |
8 | import 'dart:math' as math; |
9 | |
10 | import 'package:flutter/rendering.dart'; |
11 | |
12 | import 'basic.dart'; |
13 | import 'framework.dart'; |
14 | |
15 | /// Defines the horizontal alignment of [OverflowBar] children |
16 | /// when they're laid out in an overflow column. |
17 | /// |
18 | /// This value must be interpreted relative to the ambient |
19 | /// [TextDirection]. |
20 | enum OverflowBarAlignment { |
21 | /// Each child is left-aligned for [TextDirection.ltr], |
22 | /// right-aligned for [TextDirection.rtl]. |
23 | start, |
24 | |
25 | /// Each child is right-aligned for [TextDirection.ltr], |
26 | /// left-aligned for [TextDirection.rtl]. |
27 | end, |
28 | |
29 | /// Each child is horizontally centered. |
30 | center, |
31 | } |
32 | |
33 | /// A widget that lays out its [children] in a row unless they |
34 | /// "overflow" the available horizontal space, in which case it lays |
35 | /// them out in a column instead. |
36 | /// |
37 | /// This widget's width will expand to contain its children and the |
38 | /// specified [spacing] until it overflows. The overflow column will |
39 | /// consume all of the available width. The [overflowAlignment] |
40 | /// defines how each child will be aligned within the overflow column |
41 | /// and the [overflowSpacing] defines the gap between each child. |
42 | /// |
43 | /// The order that the children appear in the horizontal layout |
44 | /// is defined by the [textDirection], just like the [Row] widget. |
45 | /// If the layout overflows, then children's order within their |
46 | /// column is specified by [overflowDirection] instead. |
47 | /// |
48 | /// {@tool dartpad} |
49 | /// This example defines a simple approximation of a dialog |
50 | /// layout, where the layout of the dialog's action buttons are |
51 | /// defined by an [OverflowBar]. The content is wrapped in a |
52 | /// [SingleChildScrollView], so that if overflow occurs, the |
53 | /// action buttons will still be accessible by scrolling, |
54 | /// no matter how much vertical space is available. |
55 | /// |
56 | /// ** See code in examples/api/lib/widgets/overflow_bar/overflow_bar.0.dart ** |
57 | /// {@end-tool} |
58 | class OverflowBar extends MultiChildRenderObjectWidget { |
59 | /// Constructs an OverflowBar. |
60 | const OverflowBar({ |
61 | super.key, |
62 | this.spacing = 0.0, |
63 | this.alignment, |
64 | this.overflowSpacing = 0.0, |
65 | this.overflowAlignment = OverflowBarAlignment.start, |
66 | this.overflowDirection = VerticalDirection.down, |
67 | this.textDirection, |
68 | super.children, |
69 | }); |
70 | |
71 | /// The width of the gap between [children] for the default |
72 | /// horizontal layout. |
73 | /// |
74 | /// If the horizontal layout overflows, then [overflowSpacing] is |
75 | /// used instead. |
76 | /// |
77 | /// Defaults to 0.0. |
78 | final double spacing; |
79 | |
80 | /// Defines the [children]'s horizontal layout according to the same |
81 | /// rules as for [Row.mainAxisAlignment]. |
82 | /// |
83 | /// If this property is non-null, and the [children], separated by |
84 | /// [spacing], fit within the available width, then the overflow |
85 | /// bar will be as wide as possible. If the children do not fit |
86 | /// within the available width, then this property is ignored and |
87 | /// [overflowAlignment] applies instead. |
88 | /// |
89 | /// If this property is null (the default) then the overflow bar |
90 | /// will be no wider than needed to layout the [children] separated |
91 | /// by [spacing], modulo the incoming constraints. |
92 | /// |
93 | /// If [alignment] is one of [MainAxisAlignment.spaceAround], |
94 | /// [MainAxisAlignment.spaceBetween], or |
95 | /// [MainAxisAlignment.spaceEvenly], then the [spacing] parameter is |
96 | /// only used to see if the horizontal layout will overflow. |
97 | /// |
98 | /// Defaults to null. |
99 | /// |
100 | /// See also: |
101 | /// |
102 | /// * [overflowAlignment], the horizontal alignment of the [children] within |
103 | /// the vertical "overflow" layout. |
104 | /// |
105 | final MainAxisAlignment? alignment; |
106 | |
107 | /// The height of the gap between [children] in the vertical |
108 | /// "overflow" layout. |
109 | /// |
110 | /// This parameter is only used if the horizontal layout overflows, i.e. |
111 | /// if there isn't enough horizontal room for the [children] and [spacing]. |
112 | /// |
113 | /// Defaults to 0.0. |
114 | /// |
115 | /// See also: |
116 | /// |
117 | /// * [spacing], The width of the gap between each pair of children |
118 | /// for the default horizontal layout. |
119 | final double overflowSpacing; |
120 | |
121 | /// The horizontal alignment of the [children] within the vertical |
122 | /// "overflow" layout. |
123 | /// |
124 | /// This parameter is only used if the horizontal layout overflows, i.e. |
125 | /// if there isn't enough horizontal room for the [children] and [spacing]. |
126 | /// In that case the overflow bar will expand to fill the available |
127 | /// width and it will layout its [children] in a column. The |
128 | /// horizontal alignment of each child within that column is |
129 | /// defined by this parameter and the [textDirection]. If the |
130 | /// [textDirection] is [TextDirection.ltr] then each child will be |
131 | /// aligned with the left edge of the available space for |
132 | /// [OverflowBarAlignment.start], with the right edge of the |
133 | /// available space for [OverflowBarAlignment.end]. Similarly, if the |
134 | /// [textDirection] is [TextDirection.rtl] then each child will |
135 | /// be aligned with the right edge of the available space for |
136 | /// [OverflowBarAlignment.start], and with the left edge of the |
137 | /// available space for [OverflowBarAlignment.end]. For |
138 | /// [OverflowBarAlignment.center] each child is horizontally |
139 | /// centered within the available space. |
140 | /// |
141 | /// Defaults to [OverflowBarAlignment.start]. |
142 | /// |
143 | /// See also: |
144 | /// |
145 | /// * [alignment], which defines the [children]'s horizontal layout |
146 | /// (according to the same rules as for [Row.mainAxisAlignment]) when |
147 | /// the children, separated by [spacing], fit within the available space. |
148 | /// * [overflowDirection], which defines the order that the |
149 | /// [OverflowBar]'s children appear in, if the horizontal layout |
150 | /// overflows. |
151 | final OverflowBarAlignment overflowAlignment; |
152 | |
153 | /// Defines the order that the [children] appear in, if |
154 | /// the horizontal layout overflows. |
155 | /// |
156 | /// This parameter is only used if the horizontal layout overflows, i.e. |
157 | /// if there isn't enough horizontal room for the [children] and [spacing]. |
158 | /// |
159 | /// If the children do not fit into a single row, then they |
160 | /// are arranged in a column. The first child is at the top of the |
161 | /// column if this property is set to [VerticalDirection.down], since it |
162 | /// "starts" at the top and "ends" at the bottom. On the other hand, |
163 | /// the first child will be at the bottom of the column if this |
164 | /// property is set to [VerticalDirection.up], since it "starts" at the |
165 | /// bottom and "ends" at the top. |
166 | /// |
167 | /// Defaults to [VerticalDirection.down]. |
168 | /// |
169 | /// See also: |
170 | /// |
171 | /// * [overflowAlignment], which defines the horizontal alignment |
172 | /// of the children within the vertical "overflow" layout. |
173 | final VerticalDirection overflowDirection; |
174 | |
175 | /// Determines the order that the [children] appear in for the default |
176 | /// horizontal layout, and the interpretation of |
177 | /// [OverflowBarAlignment.start] and [OverflowBarAlignment.end] for |
178 | /// the vertical overflow layout. |
179 | /// |
180 | /// For the default horizontal layout, if [textDirection] is |
181 | /// [TextDirection.rtl] then the last child is laid out first. If |
182 | /// [textDirection] is [TextDirection.ltr] then the first child is |
183 | /// laid out first. |
184 | /// |
185 | /// If this parameter is null, then the value of |
186 | /// `Directionality.of(context)` is used. |
187 | /// |
188 | /// See also: |
189 | /// |
190 | /// * [overflowDirection], which defines the order that the |
191 | /// [OverflowBar]'s children appear in, if the horizontal layout |
192 | /// overflows. |
193 | /// * [Directionality], which defines the ambient directionality of |
194 | /// text and text-direction-sensitive render objects. |
195 | final TextDirection? textDirection; |
196 | |
197 | @override |
198 | RenderObject createRenderObject(BuildContext context) { |
199 | return _RenderOverflowBar( |
200 | spacing: spacing, |
201 | alignment: alignment, |
202 | overflowSpacing: overflowSpacing, |
203 | overflowAlignment: overflowAlignment, |
204 | overflowDirection: overflowDirection, |
205 | textDirection: textDirection ?? Directionality.of(context), |
206 | ); |
207 | } |
208 | |
209 | @override |
210 | void updateRenderObject(BuildContext context, RenderObject renderObject) { |
211 | (renderObject as _RenderOverflowBar) |
212 | ..spacing = spacing |
213 | ..alignment = alignment |
214 | ..overflowSpacing = overflowSpacing |
215 | ..overflowAlignment = overflowAlignment |
216 | ..overflowDirection = overflowDirection |
217 | ..textDirection = textDirection ?? Directionality.of(context); |
218 | } |
219 | |
220 | @override |
221 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
222 | super.debugFillProperties(properties); |
223 | properties.add(DoubleProperty('spacing', spacing, defaultValue: 0)); |
224 | properties.add(EnumProperty<MainAxisAlignment>('alignment', alignment, defaultValue: null)); |
225 | properties.add(DoubleProperty('overflowSpacing', overflowSpacing, defaultValue: 0)); |
226 | properties.add( |
227 | EnumProperty<OverflowBarAlignment>( |
228 | 'overflowAlignment', |
229 | overflowAlignment, |
230 | defaultValue: OverflowBarAlignment.start, |
231 | ), |
232 | ); |
233 | properties.add( |
234 | EnumProperty<VerticalDirection>( |
235 | 'overflowDirection', |
236 | overflowDirection, |
237 | defaultValue: VerticalDirection.down, |
238 | ), |
239 | ); |
240 | properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); |
241 | } |
242 | } |
243 | |
244 | class _OverflowBarParentData extends ContainerBoxParentData<RenderBox> {} |
245 | |
246 | class _RenderOverflowBar extends RenderBox |
247 | with |
248 | ContainerRenderObjectMixin<RenderBox, _OverflowBarParentData>, |
249 | RenderBoxContainerDefaultsMixin<RenderBox, _OverflowBarParentData> { |
250 | _RenderOverflowBar({ |
251 | List<RenderBox>? children, |
252 | double spacing = 0.0, |
253 | MainAxisAlignment? alignment, |
254 | double overflowSpacing = 0.0, |
255 | OverflowBarAlignment overflowAlignment = OverflowBarAlignment.start, |
256 | VerticalDirection overflowDirection = VerticalDirection.down, |
257 | required TextDirection textDirection, |
258 | }) : _spacing = spacing, |
259 | _alignment = alignment, |
260 | _overflowSpacing = overflowSpacing, |
261 | _overflowAlignment = overflowAlignment, |
262 | _overflowDirection = overflowDirection, |
263 | _textDirection = textDirection { |
264 | addAll(children); |
265 | } |
266 | |
267 | double get spacing => _spacing; |
268 | double _spacing; |
269 | set spacing(double value) { |
270 | if (_spacing == value) { |
271 | return; |
272 | } |
273 | _spacing = value; |
274 | markNeedsLayout(); |
275 | } |
276 | |
277 | MainAxisAlignment? get alignment => _alignment; |
278 | MainAxisAlignment? _alignment; |
279 | set alignment(MainAxisAlignment? value) { |
280 | if (_alignment == value) { |
281 | return; |
282 | } |
283 | _alignment = value; |
284 | markNeedsLayout(); |
285 | } |
286 | |
287 | double get overflowSpacing => _overflowSpacing; |
288 | double _overflowSpacing; |
289 | set overflowSpacing(double value) { |
290 | if (_overflowSpacing == value) { |
291 | return; |
292 | } |
293 | _overflowSpacing = value; |
294 | markNeedsLayout(); |
295 | } |
296 | |
297 | OverflowBarAlignment get overflowAlignment => _overflowAlignment; |
298 | OverflowBarAlignment _overflowAlignment; |
299 | set overflowAlignment(OverflowBarAlignment value) { |
300 | if (_overflowAlignment == value) { |
301 | return; |
302 | } |
303 | _overflowAlignment = value; |
304 | markNeedsLayout(); |
305 | } |
306 | |
307 | VerticalDirection get overflowDirection => _overflowDirection; |
308 | VerticalDirection _overflowDirection; |
309 | set overflowDirection(VerticalDirection value) { |
310 | if (_overflowDirection == value) { |
311 | return; |
312 | } |
313 | _overflowDirection = value; |
314 | markNeedsLayout(); |
315 | } |
316 | |
317 | TextDirection get textDirection => _textDirection; |
318 | TextDirection _textDirection; |
319 | set textDirection(TextDirection value) { |
320 | if (_textDirection == value) { |
321 | return; |
322 | } |
323 | _textDirection = value; |
324 | markNeedsLayout(); |
325 | } |
326 | |
327 | @override |
328 | void setupParentData(RenderBox child) { |
329 | if (child.parentData is! _OverflowBarParentData) { |
330 | child.parentData = _OverflowBarParentData(); |
331 | } |
332 | } |
333 | |
334 | @override |
335 | double computeMinIntrinsicHeight(double width) { |
336 | RenderBox? child = firstChild; |
337 | if (child == null) { |
338 | return 0; |
339 | } |
340 | double barWidth = 0.0; |
341 | while (child != null) { |
342 | barWidth += child.getMinIntrinsicWidth(double.infinity); |
343 | child = childAfter(child); |
344 | } |
345 | barWidth += spacing * (childCount - 1); |
346 | |
347 | double height = 0.0; |
348 | if (barWidth > width) { |
349 | child = firstChild; |
350 | while (child != null) { |
351 | height += child.getMinIntrinsicHeight(width); |
352 | child = childAfter(child); |
353 | } |
354 | return height + overflowSpacing * (childCount - 1); |
355 | } else { |
356 | child = firstChild; |
357 | while (child != null) { |
358 | height = math.max(height, child.getMinIntrinsicHeight(width)); |
359 | child = childAfter(child); |
360 | } |
361 | return height; |
362 | } |
363 | } |
364 | |
365 | @override |
366 | double computeMaxIntrinsicHeight(double width) { |
367 | RenderBox? child = firstChild; |
368 | if (child == null) { |
369 | return 0; |
370 | } |
371 | double barWidth = 0.0; |
372 | while (child != null) { |
373 | barWidth += child.getMinIntrinsicWidth(double.infinity); |
374 | child = childAfter(child); |
375 | } |
376 | barWidth += spacing * (childCount - 1); |
377 | |
378 | double height = 0.0; |
379 | if (barWidth > width) { |
380 | child = firstChild; |
381 | while (child != null) { |
382 | height += child.getMaxIntrinsicHeight(width); |
383 | child = childAfter(child); |
384 | } |
385 | return height + overflowSpacing * (childCount - 1); |
386 | } else { |
387 | child = firstChild; |
388 | while (child != null) { |
389 | height = math.max(height, child.getMaxIntrinsicHeight(width)); |
390 | child = childAfter(child); |
391 | } |
392 | return height; |
393 | } |
394 | } |
395 | |
396 | @override |
397 | double computeMinIntrinsicWidth(double height) { |
398 | RenderBox? child = firstChild; |
399 | if (child == null) { |
400 | return 0; |
401 | } |
402 | double width = 0.0; |
403 | while (child != null) { |
404 | width += child.getMinIntrinsicWidth(double.infinity); |
405 | child = childAfter(child); |
406 | } |
407 | return width + spacing * (childCount - 1); |
408 | } |
409 | |
410 | @override |
411 | double computeMaxIntrinsicWidth(double height) { |
412 | RenderBox? child = firstChild; |
413 | if (child == null) { |
414 | return 0; |
415 | } |
416 | double width = 0.0; |
417 | while (child != null) { |
418 | width += child.getMaxIntrinsicWidth(double.infinity); |
419 | child = childAfter(child); |
420 | } |
421 | return width + spacing * (childCount - 1); |
422 | } |
423 | |
424 | @override |
425 | double? computeDistanceToActualBaseline(TextBaseline baseline) { |
426 | return defaultComputeDistanceToHighestActualBaseline(baseline); |
427 | } |
428 | |
429 | @override |
430 | double? computeDryBaseline(BoxConstraints constraints, TextBaseline baseline) { |
431 | final BoxConstraints childConstraints = constraints.loosen(); |
432 | |
433 | final ( |
434 | RenderBox? Function(RenderBox) next, |
435 | RenderBox? startChild, |
436 | ) = switch (overflowDirection) { |
437 | VerticalDirection.down => (childAfter, firstChild), |
438 | VerticalDirection.up => (childBefore, lastChild), |
439 | }; |
440 | |
441 | double maxChildHeight = 0.0; |
442 | double y = 0.0; |
443 | double childrenWidth = 0.0; |
444 | BaselineOffset minHorizontalBaseline = BaselineOffset.noBaseline; |
445 | BaselineOffset verticalBaseline = BaselineOffset.noBaseline; |
446 | |
447 | for (RenderBox? child = startChild; child != null; child = next(child)) { |
448 | final Size childSize = child.getDryLayout(childConstraints); |
449 | final double heightDiff = childSize.height - maxChildHeight; |
450 | if (heightDiff > 0) { |
451 | minHorizontalBaseline += heightDiff / 2; |
452 | maxChildHeight = childSize.height; |
453 | } |
454 | |
455 | final BaselineOffset baselineOffset = BaselineOffset( |
456 | child.getDryBaseline(childConstraints, baseline), |
457 | ); |
458 | if (baselineOffset != null) { |
459 | verticalBaseline ??= baselineOffset + y; |
460 | minHorizontalBaseline = minHorizontalBaseline.minOf( |
461 | baselineOffset + (maxChildHeight - childSize.height), |
462 | ); |
463 | } |
464 | y += childSize.height + overflowSpacing; |
465 | childrenWidth += childSize.width; |
466 | } |
467 | |
468 | assert((verticalBaseline == null) == (minHorizontalBaseline == null)); |
469 | return childrenWidth + spacing * (childCount - 1) > constraints.maxWidth |
470 | ? verticalBaseline.offset |
471 | : minHorizontalBaseline.offset; |
472 | } |
473 | |
474 | @override |
475 | Size computeDryLayout(BoxConstraints constraints) { |
476 | RenderBox? child = firstChild; |
477 | if (child == null) { |
478 | return constraints.smallest; |
479 | } |
480 | final BoxConstraints childConstraints = constraints.loosen(); |
481 | double childrenWidth = 0.0; |
482 | double maxChildHeight = 0.0; |
483 | double y = 0.0; |
484 | while (child != null) { |
485 | final Size childSize = child.getDryLayout(childConstraints); |
486 | childrenWidth += childSize.width; |
487 | maxChildHeight = math.max(maxChildHeight, childSize.height); |
488 | y += childSize.height + overflowSpacing; |
489 | child = childAfter(child); |
490 | } |
491 | final double actualWidth = childrenWidth + spacing * (childCount - 1); |
492 | if (actualWidth > constraints.maxWidth) { |
493 | return constraints.constrain(Size(constraints.maxWidth, y - overflowSpacing)); |
494 | } else { |
495 | final double overallWidth = alignment == null ? actualWidth : constraints.maxWidth; |
496 | return constraints.constrain(Size(overallWidth, maxChildHeight)); |
497 | } |
498 | } |
499 | |
500 | @override |
501 | void performLayout() { |
502 | RenderBox? child = firstChild; |
503 | if (child == null) { |
504 | size = constraints.smallest; |
505 | return; |
506 | } |
507 | |
508 | final BoxConstraints childConstraints = constraints.loosen(); |
509 | double childrenWidth = 0; |
510 | double maxChildHeight = 0; |
511 | double maxChildWidth = 0; |
512 | |
513 | while (child != null) { |
514 | child.layout(childConstraints, parentUsesSize: true); |
515 | childrenWidth += child.size.width; |
516 | maxChildHeight = math.max(maxChildHeight, child.size.height); |
517 | maxChildWidth = math.max(maxChildWidth, child.size.width); |
518 | child = childAfter(child); |
519 | } |
520 | |
521 | final bool rtl = textDirection == TextDirection.rtl; |
522 | final double actualWidth = childrenWidth + spacing * (childCount - 1); |
523 | |
524 | if (actualWidth > constraints.maxWidth) { |
525 | // Overflow vertical layout |
526 | child = overflowDirection == VerticalDirection.down ? firstChild : lastChild; |
527 | RenderBox? nextChild() => |
528 | overflowDirection == VerticalDirection.down ? childAfter(child!) : childBefore(child!); |
529 | double y = 0; |
530 | while (child != null) { |
531 | final _OverflowBarParentData childParentData = child.parentData! as _OverflowBarParentData; |
532 | final double x = switch (overflowAlignment) { |
533 | OverflowBarAlignment.center => (constraints.maxWidth - child.size.width) / 2, |
534 | OverflowBarAlignment.start => rtl ? constraints.maxWidth - child.size.width : 0, |
535 | OverflowBarAlignment.end => rtl ? 0 : constraints.maxWidth - child.size.width, |
536 | }; |
537 | childParentData.offset = Offset(x, y); |
538 | y += child.size.height + overflowSpacing; |
539 | child = nextChild(); |
540 | } |
541 | size = constraints.constrain(Size(constraints.maxWidth, y - overflowSpacing)); |
542 | } else { |
543 | // Default horizontal layout |
544 | child = firstChild; |
545 | final double firstChildWidth = child!.size.width; |
546 | final double overallWidth = alignment == null ? actualWidth : constraints.maxWidth; |
547 | size = constraints.constrain(Size(overallWidth, maxChildHeight)); |
548 | |
549 | late double x; // initial value: origin of the first child |
550 | double layoutSpacing = spacing; // space between children |
551 | switch (alignment) { |
552 | case null: |
553 | x = rtl ? size.width - firstChildWidth : 0; |
554 | case MainAxisAlignment.start: |
555 | x = rtl ? size.width - firstChildWidth : 0; |
556 | case MainAxisAlignment.center: |
557 | final double halfRemainingWidth = (size.width - actualWidth) / 2; |
558 | x = rtl ? size.width - halfRemainingWidth - firstChildWidth : halfRemainingWidth; |
559 | case MainAxisAlignment.end: |
560 | x = rtl ? actualWidth - firstChildWidth : size.width - actualWidth; |
561 | case MainAxisAlignment.spaceBetween: |
562 | layoutSpacing = (size.width - childrenWidth) / (childCount - 1); |
563 | x = rtl ? size.width - firstChildWidth : 0; |
564 | case MainAxisAlignment.spaceAround: |
565 | layoutSpacing = childCount > 0 ? (size.width - childrenWidth) / childCount : 0; |
566 | x = rtl ? size.width - layoutSpacing / 2 - firstChildWidth : layoutSpacing / 2; |
567 | case MainAxisAlignment.spaceEvenly: |
568 | layoutSpacing = (size.width - childrenWidth) / (childCount + 1); |
569 | x = rtl ? size.width - layoutSpacing - firstChildWidth : layoutSpacing; |
570 | } |
571 | |
572 | while (child != null) { |
573 | final _OverflowBarParentData childParentData = child.parentData! as _OverflowBarParentData; |
574 | childParentData.offset = Offset(x, (maxChildHeight - child.size.height) / 2); |
575 | // x is the horizontal origin of child. To advance x to the next child's |
576 | // origin for LTR: add the width of the current child. To advance x to |
577 | // the origin of the next child for RTL: subtract the width of the next |
578 | // child (if there is one). |
579 | if (!rtl) { |
580 | x += child.size.width + layoutSpacing; |
581 | } |
582 | child = childAfter(child); |
583 | if (rtl && child != null) { |
584 | x -= child.size.width + layoutSpacing; |
585 | } |
586 | } |
587 | } |
588 | } |
589 | |
590 | @override |
591 | bool hitTestChildren(BoxHitTestResult result, {required Offset position}) { |
592 | return defaultHitTestChildren(result, position: position); |
593 | } |
594 | |
595 | @override |
596 | void paint(PaintingContext context, Offset offset) { |
597 | defaultPaint(context, offset); |
598 | } |
599 | |
600 | @override |
601 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
602 | super.debugFillProperties(properties); |
603 | properties.add(DoubleProperty('spacing', spacing, defaultValue: 0)); |
604 | properties.add(DoubleProperty('overflowSpacing', overflowSpacing, defaultValue: 0)); |
605 | properties.add( |
606 | EnumProperty<OverflowBarAlignment>( |
607 | 'overflowAlignment', |
608 | overflowAlignment, |
609 | defaultValue: OverflowBarAlignment.start, |
610 | ), |
611 | ); |
612 | properties.add( |
613 | EnumProperty<VerticalDirection>( |
614 | 'overflowDirection', |
615 | overflowDirection, |
616 | defaultValue: VerticalDirection.down, |
617 | ), |
618 | ); |
619 | properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); |
620 | } |
621 | } |
622 |
Definitions
- OverflowBarAlignment
- OverflowBar
- OverflowBar
- createRenderObject
- updateRenderObject
- debugFillProperties
- _OverflowBarParentData
- _RenderOverflowBar
- _RenderOverflowBar
- spacing
- spacing
- alignment
- alignment
- overflowSpacing
- overflowSpacing
- overflowAlignment
- overflowAlignment
- overflowDirection
- overflowDirection
- textDirection
- textDirection
- setupParentData
- computeMinIntrinsicHeight
- computeMaxIntrinsicHeight
- computeMinIntrinsicWidth
- computeMaxIntrinsicWidth
- computeDistanceToActualBaseline
- computeDryBaseline
- computeDryLayout
- performLayout
- nextChild
- hitTestChildren
- paint
Learn more about Flutter for embedded and desktop on industrialflutter.com