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 'package:flutter/widgets.dart';
6library;
7
8import 'dart:math' as math;
9
10import 'package:flutter/foundation.dart';
11
12import 'box.dart';
13import 'debug_overflow_indicator.dart';
14import 'layer.dart';
15import 'layout_helper.dart';
16import 'object.dart';
17
18// A 2D vector that uses a [RenderFlex]'s main axis and cross axis as its first and second coordinate axes.
19// It represents the same vector as (double mainAxisExtent, double crossAxisExtent).
20extension type const _AxisSize._(Size _size) {
21 _AxisSize({ required double mainAxisExtent, required double crossAxisExtent }) : this._(Size(mainAxisExtent, crossAxisExtent));
22 _AxisSize.fromSize({ required Size size, required Axis direction }) : this._(_convert(size, direction));
23
24 static const _AxisSize empty = _AxisSize._(Size.zero);
25
26 static Size _convert(Size size, Axis direction) {
27 return switch (direction) {
28 Axis.horizontal => size,
29 Axis.vertical => size.flipped,
30 };
31 }
32 double get mainAxisExtent => _size.width;
33 double get crossAxisExtent => _size.height;
34
35 Size toSize(Axis direction) => _convert(_size, direction);
36
37 _AxisSize applyConstraints(BoxConstraints constraints, Axis direction) {
38 final BoxConstraints effectiveConstraints = switch (direction) {
39 Axis.horizontal => constraints,
40 Axis.vertical => constraints.flipped,
41 };
42 return _AxisSize._(effectiveConstraints.constrain(_size));
43 }
44
45 _AxisSize operator +(_AxisSize other) => _AxisSize._(Size(_size.width + other._size.width, math.max(_size.height, other._size.height)));
46}
47
48// The ascent and descent of a baseline-aligned child.
49//
50// Baseline-aligned children contributes to the cross axis extent of a [RenderFlex]
51// differently from children with other [CrossAxisAlignment]s.
52extension type const _AscentDescent._((double ascent, double descent)? ascentDescent) {
53 factory _AscentDescent({ required double? baselineOffset, required double crossSize }) {
54 return baselineOffset == null ? none : _AscentDescent._((baselineOffset, crossSize - baselineOffset));
55 }
56 static const _AscentDescent none = _AscentDescent._(null);
57
58 double? get baselineOffset => ascentDescent?.$1;
59
60 _AscentDescent operator +(_AscentDescent other) => switch ((this, other)) {
61 (null, final _AscentDescent v) || (final _AscentDescent v, null) => v,
62 ((final double xAscent, final double xDescent),
63 (final double yAscent, final double yDescent)) => _AscentDescent._((math.max(xAscent, yAscent), math.max(xDescent, yDescent))),
64 };
65}
66
67typedef _ChildSizingFunction = double Function(RenderBox child, double extent);
68typedef _NextChild = RenderBox? Function(RenderBox child);
69
70class _LayoutSizes {
71 _LayoutSizes({
72 required this.axisSize,
73 required this.baselineOffset,
74 required this.mainAxisFreeSpace,
75 required this.spacePerFlex,
76 }) : assert(spacePerFlex?.isFinite ?? true);
77
78 // The final constrained _AxisSize of the RenderFlex.
79 final _AxisSize axisSize;
80
81 // The free space along the main axis. If the value is positive, the free space
82 // will be distributed according to the [MainAxisAlignment] specified. A
83 // negative value indicates the RenderFlex overflows along the main axis.
84 final double mainAxisFreeSpace;
85
86 // Null if the RenderFlex is not baseline aligned, or none of its children has
87 // a valid baseline of the given [TextBaseline] type.
88 final double? baselineOffset;
89
90 // The allocated space for flex children.
91 final double? spacePerFlex;
92}
93
94/// How the child is inscribed into the available space.
95///
96/// See also:
97///
98/// * [RenderFlex], the flex render object.
99/// * [Column], [Row], and [Flex], the flex widgets.
100/// * [Expanded], the widget equivalent of [tight].
101/// * [Flexible], the widget equivalent of [loose].
102enum FlexFit {
103 /// The child is forced to fill the available space.
104 ///
105 /// The [Expanded] widget assigns this kind of [FlexFit] to its child.
106 tight,
107
108 /// The child can be at most as large as the available space (but is
109 /// allowed to be smaller).
110 ///
111 /// The [Flexible] widget assigns this kind of [FlexFit] to its child.
112 loose,
113}
114
115/// Parent data for use with [RenderFlex].
116class FlexParentData extends ContainerBoxParentData<RenderBox> {
117 /// The flex factor to use for this child.
118 ///
119 /// If null or zero, the child is inflexible and determines its own size. If
120 /// non-zero, the amount of space the child's can occupy in the main axis is
121 /// determined by dividing the free space (after placing the inflexible
122 /// children) according to the flex factors of the flexible children.
123 int? flex;
124
125 /// How a flexible child is inscribed into the available space.
126 ///
127 /// If [flex] is non-zero, the [fit] determines whether the child fills the
128 /// space the parent makes available during layout. If the fit is
129 /// [FlexFit.tight], the child is required to fill the available space. If the
130 /// fit is [FlexFit.loose], the child can be at most as large as the available
131 /// space (but is allowed to be smaller).
132 FlexFit? fit;
133
134 @override
135 String toString() => '${super.toString()}; flex=$flex; fit=$fit';
136}
137
138/// How much space should be occupied in the main axis.
139///
140/// During a flex layout, available space along the main axis is allocated to
141/// children. After allocating space, there might be some remaining free space.
142/// This value controls whether to maximize or minimize the amount of free
143/// space, subject to the incoming layout constraints.
144///
145/// See also:
146///
147/// * [Column], [Row], and [Flex], the flex widgets.
148/// * [Expanded] and [Flexible], the widgets that controls a flex widgets'
149/// children's flex.
150/// * [RenderFlex], the flex render object.
151/// * [MainAxisAlignment], which controls how the free space is distributed.
152enum MainAxisSize {
153 /// Minimize the amount of free space along the main axis, subject to the
154 /// incoming layout constraints.
155 ///
156 /// If the incoming layout constraints have a large enough
157 /// [BoxConstraints.minWidth] or [BoxConstraints.minHeight], there might still
158 /// be a non-zero amount of free space.
159 ///
160 /// If the incoming layout constraints are unbounded, and any children have a
161 /// non-zero [FlexParentData.flex] and a [FlexFit.tight] fit (as applied by
162 /// [Expanded]), the [RenderFlex] will assert, because there would be infinite
163 /// remaining free space and boxes cannot be given infinite size.
164 min,
165
166 /// Maximize the amount of free space along the main axis, subject to the
167 /// incoming layout constraints.
168 ///
169 /// If the incoming layout constraints have a small enough
170 /// [BoxConstraints.maxWidth] or [BoxConstraints.maxHeight], there might still
171 /// be no free space.
172 ///
173 /// If the incoming layout constraints are unbounded, the [RenderFlex] will
174 /// assert, because there would be infinite remaining free space and boxes
175 /// cannot be given infinite size.
176 max,
177}
178
179/// How the children should be placed along the main axis in a flex layout.
180///
181/// See also:
182///
183/// * [Column], [Row], and [Flex], the flex widgets.
184/// * [RenderFlex], the flex render object.
185enum MainAxisAlignment {
186 /// Place the children as close to the start of the main axis as possible.
187 ///
188 /// If this value is used in a horizontal direction, a [TextDirection] must be
189 /// available to determine if the start is the left or the right.
190 ///
191 /// If this value is used in a vertical direction, a [VerticalDirection] must be
192 /// available to determine if the start is the top or the bottom.
193 start,
194
195 /// Place the children as close to the end of the main axis as possible.
196 ///
197 /// If this value is used in a horizontal direction, a [TextDirection] must be
198 /// available to determine if the end is the left or the right.
199 ///
200 /// If this value is used in a vertical direction, a [VerticalDirection] must be
201 /// available to determine if the end is the top or the bottom.
202 end,
203
204 /// Place the children as close to the middle of the main axis as possible.
205 center,
206
207 /// Place the free space evenly between the children.
208 spaceBetween,
209
210 /// Place the free space evenly between the children as well as half of that
211 /// space before and after the first and last child.
212 spaceAround,
213
214 /// Place the free space evenly between the children as well as before and
215 /// after the first and last child.
216 spaceEvenly;
217
218 (double leadingSpace, double betweenSpace) _distributeSpace(double freeSpace, int itemCount, bool flipped, double spacing) {
219 assert(itemCount >= 0);
220 return switch (this) {
221 MainAxisAlignment.start => flipped ? (freeSpace, spacing) : (0.0, spacing),
222
223 MainAxisAlignment.end => MainAxisAlignment.start._distributeSpace(freeSpace, itemCount, !flipped, spacing),
224 MainAxisAlignment.spaceBetween when itemCount < 2 => MainAxisAlignment.start._distributeSpace(freeSpace, itemCount, flipped, spacing),
225 MainAxisAlignment.spaceAround when itemCount == 0 => MainAxisAlignment.start._distributeSpace(freeSpace, itemCount, flipped, spacing),
226
227 MainAxisAlignment.center => (freeSpace / 2.0, spacing),
228 MainAxisAlignment.spaceBetween => (0.0, freeSpace / (itemCount - 1) + spacing),
229 MainAxisAlignment.spaceAround => (freeSpace / itemCount / 2, freeSpace / itemCount + spacing),
230 MainAxisAlignment.spaceEvenly => (freeSpace / (itemCount + 1), freeSpace / (itemCount + 1) + spacing),
231 };
232 }
233}
234
235/// How the children should be placed along the cross axis in a flex layout.
236///
237/// See also:
238///
239/// * [Column], [Row], and [Flex], the flex widgets.
240/// * [Flex.crossAxisAlignment], the property on flex widgets that
241/// has this type.
242/// * [RenderFlex], the flex render object.
243enum CrossAxisAlignment {
244 /// Place the children with their start edge aligned with the start side of
245 /// the cross axis.
246 ///
247 /// For example, in a column (a flex with a vertical axis) whose
248 /// [TextDirection] is [TextDirection.ltr], this aligns the left edge of the
249 /// children along the left edge of the column.
250 ///
251 /// If this value is used in a horizontal direction, a [TextDirection] must be
252 /// available to determine if the start is the left or the right.
253 ///
254 /// If this value is used in a vertical direction, a [VerticalDirection] must be
255 /// available to determine if the start is the top or the bottom.
256 start,
257
258 /// Place the children as close to the end of the cross axis as possible.
259 ///
260 /// For example, in a column (a flex with a vertical axis) whose
261 /// [TextDirection] is [TextDirection.ltr], this aligns the right edge of the
262 /// children along the right edge of the column.
263 ///
264 /// If this value is used in a horizontal direction, a [TextDirection] must be
265 /// available to determine if the end is the left or the right.
266 ///
267 /// If this value is used in a vertical direction, a [VerticalDirection] must be
268 /// available to determine if the end is the top or the bottom.
269 end,
270
271 /// Place the children so that their centers align with the middle of the
272 /// cross axis.
273 ///
274 /// This is the default cross-axis alignment.
275 center,
276
277 /// Require the children to fill the cross axis.
278 ///
279 /// This causes the constraints passed to the children to be tight in the
280 /// cross axis.
281 stretch,
282
283 /// Place the children along the cross axis such that their baselines match.
284 ///
285 /// Consider using this value for any horizontal main axis (as with [Row])
286 /// where the children primarily contain text. If the different children
287 /// have text with different font metrics (for example because they differ
288 /// in [TextStyle.fontSize] or other [TextStyle] properties, or because
289 /// they use different fonts due to being written in different scripts),
290 /// then this typically produces better visual alignment than the other
291 /// [CrossAxisAlignment] values, which use no information about
292 /// where the text sits vertically within its bounding box.
293 ///
294 /// The baseline of a widget is typically the typographic baseline of the
295 /// first text in the first [Text] or [RichText] widget it encloses, if any.
296 /// The typographic baseline is a horizontal line used for aligning text,
297 /// which is specified by each font; for alphabetic scripts, it ordinarily
298 /// runs along the bottom of letters excluding any descenders.
299 ///
300 /// Because baselines are always horizontal, this alignment is intended for
301 /// horizontal main axes (as with [Row]). If the main axis is vertical
302 /// (as with [Column]), then this value is treated like [start].
303 ///
304 /// For horizontal main axes, if the minimum height constraint passed to the
305 /// flex layout exceeds the intrinsic height of the cross axis, children will
306 /// be aligned as close to the top as they can be while honoring the baseline
307 /// alignment. In other words, the extra space will be below all the children.
308 ///
309 /// Children who report no baseline will be top-aligned.
310 ///
311 /// See also:
312 ///
313 /// * [RenderBox.getDistanceToBaseline], which defines the baseline of a box.
314 /// * [IgnoreBaseline], which can be used to ignore a child for the purpose of
315 /// baseline alignment.
316 baseline;
317
318 double _getChildCrossAxisOffset(double freeSpace, bool flipped) {
319 // This method should not be used to position baseline-aligned children.
320 return switch (this) {
321 CrossAxisAlignment.stretch || CrossAxisAlignment.baseline => 0.0,
322 CrossAxisAlignment.start => flipped ? freeSpace : 0.0,
323 CrossAxisAlignment.center => freeSpace / 2,
324 CrossAxisAlignment.end => CrossAxisAlignment.start._getChildCrossAxisOffset(freeSpace, !flipped),
325 };
326 }
327}
328
329/// Displays its children in a one-dimensional array.
330///
331/// ## Layout algorithm
332///
333/// _This section describes how the framework causes [RenderFlex] to position
334/// its children._
335/// _See [BoxConstraints] for an introduction to box layout models._
336///
337/// Layout for a [RenderFlex] proceeds in six steps:
338///
339/// 1. Layout each child with a null or zero flex factor with unbounded main
340/// axis constraints and the incoming cross axis constraints. If the
341/// [crossAxisAlignment] is [CrossAxisAlignment.stretch], instead use tight
342/// cross axis constraints that match the incoming max extent in the cross
343/// axis.
344/// 2. Divide the remaining main axis space among the children with non-zero
345/// flex factors according to their flex factor. For example, a child with a
346/// flex factor of 2.0 will receive twice the amount of main axis space as a
347/// child with a flex factor of 1.0.
348/// 3. Layout each of the remaining children with the same cross axis
349/// constraints as in step 1, but instead of using unbounded main axis
350/// constraints, use max axis constraints based on the amount of space
351/// allocated in step 2. Children with [Flexible.fit] properties that are
352/// [FlexFit.tight] are given tight constraints (i.e., forced to fill the
353/// allocated space), and children with [Flexible.fit] properties that are
354/// [FlexFit.loose] are given loose constraints (i.e., not forced to fill the
355/// allocated space).
356/// 4. The cross axis extent of the [RenderFlex] is the maximum cross axis
357/// extent of the children (which will always satisfy the incoming
358/// constraints).
359/// 5. The main axis extent of the [RenderFlex] is determined by the
360/// [mainAxisSize] property. If the [mainAxisSize] property is
361/// [MainAxisSize.max], then the main axis extent of the [RenderFlex] is the
362/// max extent of the incoming main axis constraints. If the [mainAxisSize]
363/// property is [MainAxisSize.min], then the main axis extent of the [Flex]
364/// is the sum of the main axis extents of the children (subject to the
365/// incoming constraints).
366/// 6. Determine the position for each child according to the
367/// [mainAxisAlignment] and the [crossAxisAlignment]. For example, if the
368/// [mainAxisAlignment] is [MainAxisAlignment.spaceBetween], any main axis
369/// space that has not been allocated to children is divided evenly and
370/// placed between the children.
371///
372/// See also:
373///
374/// * [Flex], the widget equivalent.
375/// * [Row] and [Column], direction-specific variants of [Flex].
376class RenderFlex extends RenderBox with ContainerRenderObjectMixin<RenderBox, FlexParentData>,
377 RenderBoxContainerDefaultsMixin<RenderBox, FlexParentData>,
378 DebugOverflowIndicatorMixin {
379 /// Creates a flex render object.
380 ///
381 /// By default, the flex layout is horizontal and children are aligned to the
382 /// start of the main axis and the center of the cross axis.
383 RenderFlex({
384 List<RenderBox>? children,
385 Axis direction = Axis.horizontal,
386 MainAxisSize mainAxisSize = MainAxisSize.max,
387 MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
388 CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
389 TextDirection? textDirection,
390 VerticalDirection verticalDirection = VerticalDirection.down,
391 TextBaseline? textBaseline,
392 Clip clipBehavior = Clip.none,
393 double spacing = 0.0,
394 }) : _direction = direction,
395 _mainAxisAlignment = mainAxisAlignment,
396 _mainAxisSize = mainAxisSize,
397 _crossAxisAlignment = crossAxisAlignment,
398 _textDirection = textDirection,
399 _verticalDirection = verticalDirection,
400 _textBaseline = textBaseline,
401 _clipBehavior = clipBehavior,
402 _spacing = spacing,
403 assert(spacing >= 0.0) {
404 addAll(children);
405 }
406
407 /// The direction to use as the main axis.
408 Axis get direction => _direction;
409 Axis _direction;
410 set direction(Axis value) {
411 if (_direction != value) {
412 _direction = value;
413 markNeedsLayout();
414 }
415 }
416
417 /// How the children should be placed along the main axis.
418 ///
419 /// If the [direction] is [Axis.horizontal], and the [mainAxisAlignment] is
420 /// either [MainAxisAlignment.start] or [MainAxisAlignment.end], then the
421 /// [textDirection] must not be null.
422 ///
423 /// If the [direction] is [Axis.vertical], and the [mainAxisAlignment] is
424 /// either [MainAxisAlignment.start] or [MainAxisAlignment.end], then the
425 /// [verticalDirection] must not be null.
426 MainAxisAlignment get mainAxisAlignment => _mainAxisAlignment;
427 MainAxisAlignment _mainAxisAlignment;
428 set mainAxisAlignment(MainAxisAlignment value) {
429 if (_mainAxisAlignment != value) {
430 _mainAxisAlignment = value;
431 markNeedsLayout();
432 }
433 }
434
435 /// How much space should be occupied in the main axis.
436 ///
437 /// After allocating space to children, there might be some remaining free
438 /// space. This value controls whether to maximize or minimize the amount of
439 /// free space, subject to the incoming layout constraints.
440 ///
441 /// If some children have a non-zero flex factors (and none have a fit of
442 /// [FlexFit.loose]), they will expand to consume all the available space and
443 /// there will be no remaining free space to maximize or minimize, making this
444 /// value irrelevant to the final layout.
445 MainAxisSize get mainAxisSize => _mainAxisSize;
446 MainAxisSize _mainAxisSize;
447 set mainAxisSize(MainAxisSize value) {
448 if (_mainAxisSize != value) {
449 _mainAxisSize = value;
450 markNeedsLayout();
451 }
452 }
453
454 /// How the children should be placed along the cross axis.
455 ///
456 /// If the [direction] is [Axis.horizontal], and the [crossAxisAlignment] is
457 /// either [CrossAxisAlignment.start] or [CrossAxisAlignment.end], then the
458 /// [verticalDirection] must not be null.
459 ///
460 /// If the [direction] is [Axis.vertical], and the [crossAxisAlignment] is
461 /// either [CrossAxisAlignment.start] or [CrossAxisAlignment.end], then the
462 /// [textDirection] must not be null.
463 CrossAxisAlignment get crossAxisAlignment => _crossAxisAlignment;
464 CrossAxisAlignment _crossAxisAlignment;
465 set crossAxisAlignment(CrossAxisAlignment value) {
466 if (_crossAxisAlignment != value) {
467 _crossAxisAlignment = value;
468 markNeedsLayout();
469 }
470 }
471
472 /// Determines the order to lay children out horizontally and how to interpret
473 /// `start` and `end` in the horizontal direction.
474 ///
475 /// If the [direction] is [Axis.horizontal], this controls the order in which
476 /// children are positioned (left-to-right or right-to-left), and the meaning
477 /// of the [mainAxisAlignment] property's [MainAxisAlignment.start] and
478 /// [MainAxisAlignment.end] values.
479 ///
480 /// If the [direction] is [Axis.horizontal], and either the
481 /// [mainAxisAlignment] is either [MainAxisAlignment.start] or
482 /// [MainAxisAlignment.end], or there's more than one child, then the
483 /// [textDirection] must not be null.
484 ///
485 /// If the [direction] is [Axis.vertical], this controls the meaning of the
486 /// [crossAxisAlignment] property's [CrossAxisAlignment.start] and
487 /// [CrossAxisAlignment.end] values.
488 ///
489 /// If the [direction] is [Axis.vertical], and the [crossAxisAlignment] is
490 /// either [CrossAxisAlignment.start] or [CrossAxisAlignment.end], then the
491 /// [textDirection] must not be null.
492 TextDirection? get textDirection => _textDirection;
493 TextDirection? _textDirection;
494 set textDirection(TextDirection? value) {
495 if (_textDirection != value) {
496 _textDirection = value;
497 markNeedsLayout();
498 }
499 }
500
501 /// Determines the order to lay children out vertically and how to interpret
502 /// `start` and `end` in the vertical direction.
503 ///
504 /// If the [direction] is [Axis.vertical], this controls which order children
505 /// are painted in (down or up), the meaning of the [mainAxisAlignment]
506 /// property's [MainAxisAlignment.start] and [MainAxisAlignment.end] values.
507 ///
508 /// If the [direction] is [Axis.vertical], and either the [mainAxisAlignment]
509 /// is either [MainAxisAlignment.start] or [MainAxisAlignment.end], or there's
510 /// more than one child, then the [verticalDirection] must not be null.
511 ///
512 /// If the [direction] is [Axis.horizontal], this controls the meaning of the
513 /// [crossAxisAlignment] property's [CrossAxisAlignment.start] and
514 /// [CrossAxisAlignment.end] values.
515 ///
516 /// If the [direction] is [Axis.horizontal], and the [crossAxisAlignment] is
517 /// either [CrossAxisAlignment.start] or [CrossAxisAlignment.end], then the
518 /// [verticalDirection] must not be null.
519 VerticalDirection get verticalDirection => _verticalDirection;
520 VerticalDirection _verticalDirection;
521 set verticalDirection(VerticalDirection value) {
522 if (_verticalDirection != value) {
523 _verticalDirection = value;
524 markNeedsLayout();
525 }
526 }
527
528 /// If aligning items according to their baseline, which baseline to use.
529 ///
530 /// Must not be null if [crossAxisAlignment] is [CrossAxisAlignment.baseline].
531 TextBaseline? get textBaseline => _textBaseline;
532 TextBaseline? _textBaseline;
533 set textBaseline(TextBaseline? value) {
534 assert(_crossAxisAlignment != CrossAxisAlignment.baseline || value != null);
535 if (_textBaseline != value) {
536 _textBaseline = value;
537 markNeedsLayout();
538 }
539 }
540
541 bool get _debugHasNecessaryDirections {
542 if (RenderObject.debugCheckingIntrinsics) {
543 return true;
544 }
545 if (firstChild != null && lastChild != firstChild) {
546 // i.e. there's more than one child
547 switch (direction) {
548 case Axis.horizontal:
549 assert(textDirection != null, 'Horizontal $runtimeType with multiple children has a null textDirection, so the layout order is undefined.');
550 case Axis.vertical:
551 break;
552 }
553 }
554 if (mainAxisAlignment == MainAxisAlignment.start ||
555 mainAxisAlignment == MainAxisAlignment.end) {
556 switch (direction) {
557 case Axis.horizontal:
558 assert(textDirection != null, 'Horizontal $runtimeType with $mainAxisAlignment has a null textDirection, so the alignment cannot be resolved.');
559 case Axis.vertical:
560 break;
561 }
562 }
563 if (crossAxisAlignment == CrossAxisAlignment.start ||
564 crossAxisAlignment == CrossAxisAlignment.end) {
565 switch (direction) {
566 case Axis.horizontal:
567 break;
568 case Axis.vertical:
569 assert(textDirection != null, 'Vertical $runtimeType with $crossAxisAlignment has a null textDirection, so the alignment cannot be resolved.');
570 }
571 }
572 return true;
573 }
574
575 // Set during layout if overflow occurred on the main axis.
576 double _overflow = 0;
577 // Check whether any meaningful overflow is present. Values below an epsilon
578 // are treated as not overflowing.
579 bool get _hasOverflow => _overflow > precisionErrorTolerance;
580
581 /// {@macro flutter.material.Material.clipBehavior}
582 ///
583 /// Defaults to [Clip.none].
584 Clip get clipBehavior => _clipBehavior;
585 Clip _clipBehavior = Clip.none;
586 set clipBehavior(Clip value) {
587 if (value != _clipBehavior) {
588 _clipBehavior = value;
589 markNeedsPaint();
590 markNeedsSemanticsUpdate();
591 }
592 }
593
594 /// {@template flutter.rendering.RenderFlex.spacing}
595 /// How much space to place between children in the main axis.
596 ///
597 /// The spacing is only applied between children in the main axis.
598 ///
599 /// If the [spacing] is 10.0 and the [mainAxisAlignment] is
600 /// [MainAxisAlignment.start], then the first child will be placed at the start
601 /// of the main axis, and the second child will be placed 10.0 pixels after
602 /// the first child in the main axis, and so on. The [spacing] is not applied
603 /// before the first child or after the last child.
604 ///
605 /// If the [spacing] is 10.0 and the [mainAxisAlignment] is [MainAxisAlignment.end],
606 /// then the last child will be placed at the end of the main axis, and the
607 /// second-to-last child will be placed 10.0 pixels before the last child in
608 /// the main axis, and so on. The [spacing] is not applied before the first
609 /// child or after the last child.
610 ///
611 /// If the [spacing] is 10.0 and the [mainAxisAlignment] is [MainAxisAlignment.center],
612 /// then the children will be placed in the center of the main axis with 10.0
613 /// pixels of space between the children. The [spacing] is not applied before the first
614 /// child or after the last child.
615 ///
616 /// If the [spacing] is 10.0 and the [mainAxisAlignment] is [MainAxisAlignment.spaceBetween],
617 /// then there will be a minimum of 10.0 pixels of space between each child in the
618 /// main axis. If the free space is 100.0 pixels between the two children,
619 /// then the minimum space between the children will be 10.0 pixels and the
620 /// remaining 90.0 pixels will be the free space between the children. The
621 /// [spacing] is not applied before the first child or after the last child.
622 ///
623 /// If the [spacing] is 10.0 and the [mainAxisAlignment] is [MainAxisAlignment.spaceAround],
624 /// then there will be a minimum of 10.0 pixels of space between each child in the
625 /// main axis, and the remaining free space will be placed between the children as
626 /// well as before the first child and after the last child. The [spacing] is
627 /// not applied before the first child or after the last child.
628 ///
629 /// If the [spacing] is 10.0 and the [mainAxisAlignment] is [MainAxisAlignment.spaceEvenly],
630 /// then there will be a minimum of 10.0 pixels of space between each child in the
631 /// main axis, and the remaining free space will be evenly placed between the
632 /// children as well as before the first child and after the last child. The
633 /// [spacing] is not applied before the first child or after the last child.
634 ///
635 /// When the [spacing] is non-zero, the layout size will be larger than
636 /// the sum of the children's layout sizes in the main axis.
637 ///
638 /// When the total children's layout sizes and total spacing between the
639 /// children is greater than the maximum constraints in the main axis, then
640 /// the children will overflow. For example, if there are two children and the
641 /// maximum constraint is 100.0 pixels, the children's layout sizes are 50.0
642 /// pixels each, and the spacing is 10.0 pixels, then the children will
643 /// overflow by 10.0 pixels.
644 ///
645 /// Defaults to 0.0.
646 /// {@endtemplate}
647 double get spacing => _spacing;
648 double _spacing;
649 set spacing (double value) {
650 if (_spacing == value) {
651 return;
652 }
653 _spacing = value;
654 markNeedsLayout();
655 }
656
657 @override
658 void setupParentData(RenderBox child) {
659 if (child.parentData is! FlexParentData) {
660 child.parentData = FlexParentData();
661 }
662 }
663
664 double _getIntrinsicSize({
665 required Axis sizingDirection,
666 required double extent, // The extent in the direction that isn't the sizing direction.
667 required _ChildSizingFunction childSize, // A method to find the size in the sizing direction.
668 }) {
669 if (_direction == sizingDirection) {
670 // INTRINSIC MAIN SIZE
671 // Intrinsic main size is the smallest size the flex container can take
672 // while maintaining the min/max-content contributions of its flex items.
673 double totalFlex = 0.0;
674 double inflexibleSpace = spacing * (childCount - 1);
675 double maxFlexFractionSoFar = 0.0;
676 for (RenderBox? child = firstChild; child != null; child = childAfter(child)) {
677 final int flex = _getFlex(child);
678 totalFlex += flex;
679 if (flex > 0) {
680 final double flexFraction = childSize(child, extent) / flex;
681 maxFlexFractionSoFar = math.max(maxFlexFractionSoFar, flexFraction);
682 } else {
683 inflexibleSpace += childSize(child, extent);
684 }
685 }
686 return maxFlexFractionSoFar * totalFlex + inflexibleSpace;
687 } else {
688 // INTRINSIC CROSS SIZE
689 // Intrinsic cross size is the max of the intrinsic cross sizes of the
690 // children, after the flexible children are fit into the available space,
691 // with the children sized using their max intrinsic dimensions.
692 final bool isHorizontal = switch (direction) {
693 Axis.horizontal => true,
694 Axis.vertical => false,
695 };
696
697 Size layoutChild(RenderBox child, BoxConstraints constraints) {
698 final double mainAxisSizeFromConstraints = isHorizontal ? constraints.maxWidth : constraints.maxHeight;
699 // A infinite mainAxisSizeFromConstraints means this child is flexible (or extent is double.infinity).
700 assert((_getFlex(child) != 0 && extent.isFinite) == mainAxisSizeFromConstraints.isFinite);
701 final double maxMainAxisSize = mainAxisSizeFromConstraints.isFinite
702 ? mainAxisSizeFromConstraints
703 : (isHorizontal ? child.getMaxIntrinsicWidth(double.infinity) : child.getMaxIntrinsicHeight(double.infinity));
704 return isHorizontal
705 ? Size(maxMainAxisSize, childSize(child, maxMainAxisSize))
706 : Size(childSize(child, maxMainAxisSize), maxMainAxisSize);
707 }
708 return _computeSizes(
709 constraints: isHorizontal ? BoxConstraints(maxWidth: extent) : BoxConstraints(maxHeight: extent),
710 layoutChild: layoutChild,
711 getBaseline: ChildLayoutHelper.getDryBaseline,
712 ).axisSize.crossAxisExtent;
713 }
714 }
715
716 @override
717 double computeMinIntrinsicWidth(double height) {
718 return _getIntrinsicSize(
719 sizingDirection: Axis.horizontal,
720 extent: height,
721 childSize: (RenderBox child, double extent) => child.getMinIntrinsicWidth(extent),
722 );
723 }
724
725 @override
726 double computeMaxIntrinsicWidth(double height) {
727 return _getIntrinsicSize(
728 sizingDirection: Axis.horizontal,
729 extent: height,
730 childSize: (RenderBox child, double extent) => child.getMaxIntrinsicWidth(extent),
731 );
732 }
733
734 @override
735 double computeMinIntrinsicHeight(double width) {
736 return _getIntrinsicSize(
737 sizingDirection: Axis.vertical,
738 extent: width,
739 childSize: (RenderBox child, double extent) => child.getMinIntrinsicHeight(extent),
740 );
741 }
742
743 @override
744 double computeMaxIntrinsicHeight(double width) {
745 return _getIntrinsicSize(
746 sizingDirection: Axis.vertical,
747 extent: width,
748 childSize: (RenderBox child, double extent) => child.getMaxIntrinsicHeight(extent),
749 );
750 }
751
752 @override
753 double? computeDistanceToActualBaseline(TextBaseline baseline) {
754 return switch (_direction) {
755 Axis.horizontal => defaultComputeDistanceToHighestActualBaseline(baseline),
756 Axis.vertical => defaultComputeDistanceToFirstActualBaseline(baseline),
757 };
758 }
759
760 static int _getFlex(RenderBox child) {
761 final FlexParentData childParentData = child.parentData! as FlexParentData;
762 return childParentData.flex ?? 0;
763 }
764
765 static FlexFit _getFit(RenderBox child) {
766 final FlexParentData childParentData = child.parentData! as FlexParentData;
767 return childParentData.fit ?? FlexFit.tight;
768 }
769
770 bool get _isBaselineAligned {
771 return switch (crossAxisAlignment) {
772 CrossAxisAlignment.baseline => switch (direction) {
773 Axis.horizontal => true,
774 Axis.vertical => false,
775 },
776 CrossAxisAlignment.start || CrossAxisAlignment.center || CrossAxisAlignment.end || CrossAxisAlignment.stretch => false,
777 };
778 }
779
780 double _getCrossSize(Size size) {
781 return switch (_direction) {
782 Axis.horizontal => size.height,
783 Axis.vertical => size.width,
784 };
785 }
786
787 double _getMainSize(Size size) {
788 return switch (_direction) {
789 Axis.horizontal => size.width,
790 Axis.vertical => size.height,
791 };
792 }
793
794 // flipMainAxis is used to decide whether to lay out
795 // left-to-right/top-to-bottom (false), or right-to-left/bottom-to-top
796 // (true). Returns false in cases when the layout direction does not matter
797 // (for instance, there is no child).
798 bool get _flipMainAxis => firstChild != null && switch (direction) {
799 Axis.horizontal => switch (textDirection) {
800 null || TextDirection.ltr => false,
801 TextDirection.rtl => true,
802 },
803 Axis.vertical => switch (verticalDirection) {
804 VerticalDirection.down => false,
805 VerticalDirection.up => true,
806 },
807 };
808
809 bool get _flipCrossAxis => firstChild != null && switch (direction) {
810 Axis.vertical => switch (textDirection) {
811 null || TextDirection.ltr => false,
812 TextDirection.rtl => true,
813 },
814 Axis.horizontal => switch (verticalDirection) {
815 VerticalDirection.down => false,
816 VerticalDirection.up => true,
817 },
818 };
819
820 BoxConstraints _constraintsForNonFlexChild(BoxConstraints constraints) {
821 final bool fillCrossAxis = switch (crossAxisAlignment) {
822 CrossAxisAlignment.stretch => true,
823 CrossAxisAlignment.start ||
824 CrossAxisAlignment.center ||
825 CrossAxisAlignment.end ||
826 CrossAxisAlignment.baseline => false,
827 };
828 return switch (_direction) {
829 Axis.horizontal => fillCrossAxis
830 ? BoxConstraints.tightFor(height: constraints.maxHeight)
831 : BoxConstraints(maxHeight: constraints.maxHeight),
832 Axis.vertical => fillCrossAxis
833 ? BoxConstraints.tightFor(width: constraints.maxWidth)
834 : BoxConstraints(maxWidth: constraints.maxWidth),
835 };
836 }
837
838 BoxConstraints _constraintsForFlexChild(RenderBox child, BoxConstraints constraints, double maxChildExtent) {
839 assert(_getFlex(child) > 0.0);
840 assert(maxChildExtent >= 0.0);
841 final double minChildExtent = switch (_getFit(child)) {
842 FlexFit.tight => maxChildExtent,
843 FlexFit.loose => 0.0,
844 };
845 final bool fillCrossAxis = switch (crossAxisAlignment) {
846 CrossAxisAlignment.stretch => true,
847 CrossAxisAlignment.start ||
848 CrossAxisAlignment.center ||
849 CrossAxisAlignment.end ||
850 CrossAxisAlignment.baseline => false,
851 };
852 return switch (_direction) {
853 Axis.horizontal => BoxConstraints(
854 minWidth: minChildExtent,
855 maxWidth: maxChildExtent,
856 minHeight: fillCrossAxis ? constraints.maxHeight : 0.0,
857 maxHeight: constraints.maxHeight,
858 ),
859 Axis.vertical => BoxConstraints(
860 minWidth: fillCrossAxis ? constraints.maxWidth : 0.0,
861 maxWidth: constraints.maxWidth,
862 minHeight: minChildExtent,
863 maxHeight: maxChildExtent,
864 ),
865 };
866 }
867
868 @override
869 double? computeDryBaseline(BoxConstraints constraints, TextBaseline baseline) {
870 final _LayoutSizes sizes = _computeSizes(
871 constraints: constraints,
872 layoutChild: ChildLayoutHelper.dryLayoutChild,
873 getBaseline: ChildLayoutHelper.getDryBaseline,
874 );
875
876 if (_isBaselineAligned) {
877 return sizes.baselineOffset;
878 }
879
880 final BoxConstraints nonFlexConstraints = _constraintsForNonFlexChild(constraints);
881 BoxConstraints constraintsForChild(RenderBox child) {
882 final double? spacePerFlex = sizes.spacePerFlex;
883 final int flex;
884 return spacePerFlex != null && (flex = _getFlex(child)) > 0
885 ? _constraintsForFlexChild(child, constraints, flex * spacePerFlex)
886 : nonFlexConstraints;
887 }
888
889 BaselineOffset baselineOffset = BaselineOffset.noBaseline;
890 switch (direction) {
891 case Axis.vertical:
892 final double freeSpace = math.max(0.0, sizes.mainAxisFreeSpace);
893 final bool flipMainAxis = _flipMainAxis;
894 final (double leadingSpaceY, double spaceBetween) = mainAxisAlignment._distributeSpace(freeSpace, childCount, flipMainAxis, spacing);
895 double y = flipMainAxis
896 ? leadingSpaceY + (childCount - 1) * spaceBetween + (sizes.axisSize.mainAxisExtent - sizes.mainAxisFreeSpace)
897 : leadingSpaceY;
898 final double directionUnit = flipMainAxis ? -1.0 : 1.0;
899 for (RenderBox? child = firstChild; baselineOffset == BaselineOffset.noBaseline && child != null; child = childAfter(child)) {
900 final BoxConstraints childConstraints = constraintsForChild(child);
901 final Size childSize = child.getDryLayout(childConstraints);
902 final double? childBaselineOffset = child.getDryBaseline(childConstraints, baseline);
903 final double additionalY = flipMainAxis ? - childSize.height : 0.0;
904 baselineOffset = BaselineOffset(childBaselineOffset) + y + additionalY;
905 y += directionUnit * (spaceBetween + childSize.height);
906 }
907 case Axis.horizontal:
908 final bool flipCrossAxis = _flipCrossAxis;
909 for (RenderBox? child = firstChild; child != null; child = childAfter(child)) {
910 final BoxConstraints childConstraints = constraintsForChild(child);
911 final BaselineOffset distance = BaselineOffset(child.getDryBaseline(childConstraints, baseline));
912 final double freeCrossAxisSpace = sizes.axisSize.crossAxisExtent - child.getDryLayout(childConstraints).height;
913 final BaselineOffset childBaseline = distance + crossAxisAlignment._getChildCrossAxisOffset(freeCrossAxisSpace, flipCrossAxis);
914 baselineOffset = baselineOffset.minOf(childBaseline);
915 }
916 }
917 return baselineOffset.offset;
918 }
919
920 @override
921 @protected
922 Size computeDryLayout(covariant BoxConstraints constraints) {
923 FlutterError? constraintsError;
924 assert(() {
925 constraintsError = _debugCheckConstraints(
926 constraints: constraints,
927 reportParentConstraints: false,
928 );
929 return true;
930 }());
931 if (constraintsError != null) {
932 assert(debugCannotComputeDryLayout(error: constraintsError));
933 return Size.zero;
934 }
935
936 return _computeSizes(
937 constraints: constraints,
938 layoutChild: ChildLayoutHelper.dryLayoutChild,
939 getBaseline: ChildLayoutHelper.getDryBaseline,
940 ).axisSize.toSize(direction);
941 }
942
943 FlutterError? _debugCheckConstraints({required BoxConstraints constraints, required bool reportParentConstraints}) {
944 FlutterError? result;
945 assert(() {
946 final double maxMainSize = _direction == Axis.horizontal ? constraints.maxWidth : constraints.maxHeight;
947 final bool canFlex = maxMainSize < double.infinity;
948 RenderBox? child = firstChild;
949 while (child != null) {
950 final int flex = _getFlex(child);
951 if (flex > 0) {
952 final String identity = _direction == Axis.horizontal ? 'row' : 'column';
953 final String axis = _direction == Axis.horizontal ? 'horizontal' : 'vertical';
954 final String dimension = _direction == Axis.horizontal ? 'width' : 'height';
955 DiagnosticsNode error, message;
956 final List<DiagnosticsNode> addendum = <DiagnosticsNode>[];
957 if (!canFlex && (mainAxisSize == MainAxisSize.max || _getFit(child) == FlexFit.tight)) {
958 error = ErrorSummary('RenderFlex children have non-zero flex but incoming $dimension constraints are unbounded.');
959 message = ErrorDescription(
960 'When a $identity is in a parent that does not provide a finite $dimension constraint, for example '
961 'if it is in a $axis scrollable, it will try to shrink-wrap its children along the $axis '
962 'axis. Setting a flex on a child (e.g. using Expanded) indicates that the child is to '
963 'expand to fill the remaining space in the $axis direction.',
964 );
965 if (reportParentConstraints) { // Constraints of parents are unavailable in dry layout.
966 RenderBox? node = this;
967 switch (_direction) {
968 case Axis.horizontal:
969 while (!node!.constraints.hasBoundedWidth && node.parent is RenderBox) {
970 node = node.parent! as RenderBox;
971 }
972 if (!node.constraints.hasBoundedWidth) {
973 node = null;
974 }
975 case Axis.vertical:
976 while (!node!.constraints.hasBoundedHeight && node.parent is RenderBox) {
977 node = node.parent! as RenderBox;
978 }
979 if (!node.constraints.hasBoundedHeight) {
980 node = null;
981 }
982 }
983 if (node != null) {
984 addendum.add(node.describeForError('The nearest ancestor providing an unbounded width constraint is'));
985 }
986 }
987 addendum.add(ErrorHint('See also: https://flutter.dev/unbounded-constraints'));
988 } else {
989 return true;
990 }
991 result = FlutterError.fromParts(<DiagnosticsNode>[
992 error,
993 message,
994 ErrorDescription(
995 'These two directives are mutually exclusive. If a parent is to shrink-wrap its child, the child '
996 'cannot simultaneously expand to fit its parent.',
997 ),
998 ErrorHint(
999 'Consider setting mainAxisSize to MainAxisSize.min and using FlexFit.loose fits for the flexible '
1000 'children (using Flexible rather than Expanded). This will allow the flexible children '
1001 'to size themselves to less than the infinite remaining space they would otherwise be '
1002 'forced to take, and then will cause the RenderFlex to shrink-wrap the children '
1003 'rather than expanding to fit the maximum constraints provided by the parent.',
1004 ),
1005 ErrorDescription(
1006 'If this message did not help you determine the problem, consider using debugDumpRenderTree():\n'
1007 ' https://flutter.dev/to/debug-render-layer\n'
1008 ' https://api.flutter.dev/flutter/rendering/debugDumpRenderTree.html',
1009 ),
1010 describeForError('The affected RenderFlex is', style: DiagnosticsTreeStyle.errorProperty),
1011 DiagnosticsProperty<dynamic>('The creator information is set to', debugCreator, style: DiagnosticsTreeStyle.errorProperty),
1012 ...addendum,
1013 ErrorDescription(
1014 "If none of the above helps enough to fix this problem, please don't hesitate to file a bug:\n"
1015 ' https://github.com/flutter/flutter/issues/new?template=2_bug.yml',
1016 ),
1017 ]);
1018 return true;
1019 }
1020 child = childAfter(child);
1021 }
1022 return true;
1023 }());
1024 return result;
1025 }
1026
1027 _LayoutSizes _computeSizes({
1028 required BoxConstraints constraints,
1029 required ChildLayouter layoutChild,
1030 required ChildBaselineGetter getBaseline,
1031 }) {
1032 assert(_debugHasNecessaryDirections);
1033
1034 // Determine used flex factor, size inflexible items, calculate free space.
1035 final double maxMainSize = _getMainSize(constraints.biggest);
1036 final bool canFlex = maxMainSize.isFinite;
1037 final BoxConstraints nonFlexChildConstraints = _constraintsForNonFlexChild(constraints);
1038 // Null indicates the children are not baseline aligned.
1039 final TextBaseline? textBaseline = _isBaselineAligned
1040 ? (this.textBaseline ?? (throw FlutterError('To use CrossAxisAlignment.baseline, you must also specify which baseline to use using the "textBaseline" argument.')))
1041 : null;
1042
1043 // The first pass lays out non-flex children and computes total flex.
1044 int totalFlex = 0;
1045 RenderBox? firstFlexChild;
1046 _AscentDescent accumulatedAscentDescent = _AscentDescent.none;
1047 // Initially, accumulatedSize is the sum of the spaces between children in the main axis.
1048 _AxisSize accumulatedSize = _AxisSize._(Size(spacing * (childCount - 1), 0.0));
1049 for (RenderBox? child = firstChild; child != null; child = childAfter(child)) {
1050 final int flex;
1051 if (canFlex && (flex = _getFlex(child)) > 0) {
1052 totalFlex += flex;
1053 firstFlexChild ??= child;
1054 } else {
1055 final _AxisSize childSize = _AxisSize.fromSize(size: layoutChild(child, nonFlexChildConstraints), direction: direction);
1056 accumulatedSize += childSize;
1057 // Baseline-aligned children contributes to the cross axis extent separately.
1058 final double? baselineOffset = textBaseline == null ? null : getBaseline(child, nonFlexChildConstraints, textBaseline);
1059 accumulatedAscentDescent += _AscentDescent(baselineOffset: baselineOffset, crossSize: childSize.crossAxisExtent);
1060 }
1061 }
1062
1063 assert((totalFlex == 0) == (firstFlexChild == null));
1064 assert(firstFlexChild == null || canFlex); // If we are given infinite space there's no need for this extra step.
1065
1066 // The second pass distributes free space to flexible children.
1067 final double flexSpace = math.max(0.0, maxMainSize - accumulatedSize.mainAxisExtent);
1068 final double spacePerFlex = flexSpace / totalFlex;
1069 for (RenderBox? child = firstFlexChild; child != null && totalFlex > 0; child = childAfter(child)) {
1070 final int flex = _getFlex(child);
1071 if (flex == 0) {
1072 continue;
1073 }
1074 totalFlex -= flex;
1075 assert(spacePerFlex.isFinite);
1076 final double maxChildExtent = spacePerFlex * flex;
1077 assert(_getFit(child) == FlexFit.loose || maxChildExtent < double.infinity);
1078 final BoxConstraints childConstraints = _constraintsForFlexChild(child, constraints, maxChildExtent);
1079 final _AxisSize childSize = _AxisSize.fromSize(size: layoutChild(child, childConstraints), direction: direction);
1080 accumulatedSize += childSize;
1081 final double? baselineOffset = textBaseline == null ? null : getBaseline(child, childConstraints, textBaseline);
1082 accumulatedAscentDescent += _AscentDescent(baselineOffset: baselineOffset, crossSize: childSize.crossAxisExtent);
1083 }
1084 assert(totalFlex == 0);
1085
1086 // The overall height of baseline-aligned children contributes to the cross axis extent.
1087 accumulatedSize += switch (accumulatedAscentDescent) {
1088 null => _AxisSize.empty,
1089 (final double ascent, final double descent) => _AxisSize(mainAxisExtent: 0, crossAxisExtent: ascent + descent),
1090 };
1091
1092 final double idealMainSize = switch (mainAxisSize) {
1093 MainAxisSize.max when maxMainSize.isFinite => maxMainSize,
1094 MainAxisSize.max || MainAxisSize.min => accumulatedSize.mainAxisExtent,
1095 };
1096
1097 final _AxisSize constrainedSize = _AxisSize(mainAxisExtent: idealMainSize, crossAxisExtent: accumulatedSize.crossAxisExtent)
1098 .applyConstraints(constraints, direction);
1099 return _LayoutSizes(
1100 axisSize: constrainedSize,
1101 mainAxisFreeSpace: constrainedSize.mainAxisExtent - accumulatedSize.mainAxisExtent,
1102 baselineOffset: accumulatedAscentDescent.baselineOffset,
1103 spacePerFlex: firstFlexChild == null ? null : spacePerFlex,
1104 );
1105 }
1106
1107 @override
1108 void performLayout() {
1109 final BoxConstraints constraints = this.constraints;
1110 assert(() {
1111 final FlutterError? constraintsError = _debugCheckConstraints(
1112 constraints: constraints,
1113 reportParentConstraints: true,
1114 );
1115 if (constraintsError != null) {
1116 throw constraintsError;
1117 }
1118 return true;
1119 }());
1120
1121 final _LayoutSizes sizes = _computeSizes(
1122 constraints: constraints,
1123 layoutChild: ChildLayoutHelper.layoutChild,
1124 getBaseline: ChildLayoutHelper.getBaseline,
1125 );
1126
1127 final double crossAxisExtent = sizes.axisSize.crossAxisExtent;
1128 size = sizes.axisSize.toSize(direction);
1129 _overflow = math.max(0.0, -sizes.mainAxisFreeSpace);
1130
1131 final double remainingSpace = math.max(0.0, sizes.mainAxisFreeSpace);
1132 final bool flipMainAxis = _flipMainAxis;
1133 final bool flipCrossAxis = _flipCrossAxis;
1134 final (double leadingSpace, double betweenSpace) = mainAxisAlignment._distributeSpace(remainingSpace, childCount, flipMainAxis, spacing);
1135 final (_NextChild nextChild, RenderBox? topLeftChild) = flipMainAxis ? (childBefore, lastChild) : (childAfter, firstChild);
1136 final double? baselineOffset = sizes.baselineOffset;
1137 assert(baselineOffset == null || (crossAxisAlignment == CrossAxisAlignment.baseline && direction == Axis.horizontal));
1138
1139 // Position all children in visual order: starting from the top-left child and
1140 // work towards the child that's farthest away from the origin.
1141 double childMainPosition = leadingSpace;
1142 for (RenderBox? child = topLeftChild; child != null; child = nextChild(child)) {
1143 final double? childBaselineOffset;
1144 final bool baselineAlign = baselineOffset != null
1145 && (childBaselineOffset = child.getDistanceToBaseline(textBaseline!, onlyReal: true)) != null;
1146 final double childCrossPosition = baselineAlign
1147 ? baselineOffset - childBaselineOffset!
1148 : crossAxisAlignment._getChildCrossAxisOffset(crossAxisExtent - _getCrossSize(child.size), flipCrossAxis);
1149 final FlexParentData childParentData = child.parentData! as FlexParentData;
1150 childParentData.offset = switch (direction) {
1151 Axis.horizontal => Offset(childMainPosition, childCrossPosition),
1152 Axis.vertical => Offset(childCrossPosition, childMainPosition),
1153 };
1154 childMainPosition += _getMainSize(child.size) + betweenSpace;
1155 }
1156 }
1157
1158 @override
1159 bool hitTestChildren(BoxHitTestResult result, { required Offset position }) {
1160 return defaultHitTestChildren(result, position: position);
1161 }
1162
1163 @override
1164 void paint(PaintingContext context, Offset offset) {
1165 if (!_hasOverflow) {
1166 defaultPaint(context, offset);
1167 return;
1168 }
1169
1170 // There's no point in drawing the children if we're empty.
1171 if (size.isEmpty) {
1172 return;
1173 }
1174
1175 _clipRectLayer.layer = context.pushClipRect(
1176 needsCompositing,
1177 offset,
1178 Offset.zero & size,
1179 defaultPaint,
1180 clipBehavior: clipBehavior,
1181 oldLayer: _clipRectLayer.layer,
1182 );
1183
1184 assert(() {
1185 final List<DiagnosticsNode> debugOverflowHints = <DiagnosticsNode>[
1186 ErrorDescription(
1187 'The overflowing $runtimeType has an orientation of $_direction.',
1188 ),
1189 ErrorDescription(
1190 'The edge of the $runtimeType that is overflowing has been marked '
1191 'in the rendering with a yellow and black striped pattern. This is '
1192 'usually caused by the contents being too big for the $runtimeType.',
1193 ),
1194 ErrorHint(
1195 'Consider applying a flex factor (e.g. using an Expanded widget) to '
1196 'force the children of the $runtimeType to fit within the available '
1197 'space instead of being sized to their natural size.',
1198 ),
1199 ErrorHint(
1200 'This is considered an error condition because it indicates that there '
1201 'is content that cannot be seen. If the content is legitimately bigger '
1202 'than the available space, consider clipping it with a ClipRect widget '
1203 'before putting it in the flex, or using a scrollable container rather '
1204 'than a Flex, like a ListView.',
1205 ),
1206 ];
1207
1208 // Simulate a child rect that overflows by the right amount. This child
1209 // rect is never used for drawing, just for determining the overflow
1210 // location and amount.
1211 final Rect overflowChildRect = switch (_direction) {
1212 Axis.horizontal => Rect.fromLTWH(0.0, 0.0, size.width + _overflow, 0.0),
1213 Axis.vertical => Rect.fromLTWH(0.0, 0.0, 0.0, size.height + _overflow),
1214 };
1215 paintOverflowIndicator(context, offset, Offset.zero & size, overflowChildRect, overflowHints: debugOverflowHints);
1216 return true;
1217 }());
1218 }
1219
1220 final LayerHandle<ClipRectLayer> _clipRectLayer = LayerHandle<ClipRectLayer>();
1221
1222 @override
1223 void dispose() {
1224 _clipRectLayer.layer = null;
1225 super.dispose();
1226 }
1227
1228 @override
1229 Rect? describeApproximatePaintClip(RenderObject child) {
1230 switch (clipBehavior) {
1231 case Clip.none:
1232 return null;
1233 case Clip.hardEdge:
1234 case Clip.antiAlias:
1235 case Clip.antiAliasWithSaveLayer:
1236 return _hasOverflow ? Offset.zero & size : null;
1237 }
1238 }
1239
1240
1241 @override
1242 String toStringShort() {
1243 String header = super.toStringShort();
1244 if (!kReleaseMode) {
1245 if (_hasOverflow) {
1246 header += ' OVERFLOWING';
1247 }
1248 }
1249 return header;
1250 }
1251
1252 @override
1253 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1254 super.debugFillProperties(properties);
1255 properties.add(EnumProperty<Axis>('direction', direction));
1256 properties.add(EnumProperty<MainAxisAlignment>('mainAxisAlignment', mainAxisAlignment));
1257 properties.add(EnumProperty<MainAxisSize>('mainAxisSize', mainAxisSize));
1258 properties.add(EnumProperty<CrossAxisAlignment>('crossAxisAlignment', crossAxisAlignment));
1259 properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
1260 properties.add(EnumProperty<VerticalDirection>('verticalDirection', verticalDirection, defaultValue: null));
1261 properties.add(EnumProperty<TextBaseline>('textBaseline', textBaseline, defaultValue: null));
1262 properties.add(DoubleProperty('spacing', spacing, defaultValue: null));
1263 }
1264}
1265