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
5import 'dart:math' as math;
6import 'dart:ui' as ui show Image, ImageFilter, TextHeightBehavior;
7
8import 'package:flutter/animation.dart';
9import 'package:flutter/foundation.dart';
10import 'package:flutter/gestures.dart';
11import 'package:flutter/rendering.dart';
12import 'package:flutter/services.dart';
13
14import 'binding.dart';
15import 'debug.dart';
16import 'framework.dart';
17import 'localizations.dart';
18import 'visibility.dart';
19import 'widget_span.dart';
20
21export 'package:flutter/animation.dart';
22export 'package:flutter/foundation.dart' show
23 ChangeNotifier,
24 FlutterErrorDetails,
25 Listenable,
26 TargetPlatform,
27 ValueNotifier;
28export 'package:flutter/painting.dart';
29export 'package:flutter/rendering.dart' show
30 AlignmentGeometryTween,
31 AlignmentTween,
32 Axis,
33 BoxConstraints,
34 BoxConstraintsTransform,
35 CrossAxisAlignment,
36 CustomClipper,
37 CustomPainter,
38 CustomPainterSemantics,
39 DecorationPosition,
40 FlexFit,
41 FlowDelegate,
42 FlowPaintingContext,
43 FractionalOffsetTween,
44 HitTestBehavior,
45 LayerLink,
46 MainAxisAlignment,
47 MainAxisSize,
48 MouseCursor,
49 MultiChildLayoutDelegate,
50 PaintingContext,
51 PointerCancelEvent,
52 PointerCancelEventListener,
53 PointerDownEvent,
54 PointerDownEventListener,
55 PointerEvent,
56 PointerMoveEvent,
57 PointerMoveEventListener,
58 PointerUpEvent,
59 PointerUpEventListener,
60 RelativeRect,
61 SemanticsBuilderCallback,
62 ShaderCallback,
63 ShapeBorderClipper,
64 SingleChildLayoutDelegate,
65 StackFit,
66 SystemMouseCursors,
67 TextOverflow,
68 ValueChanged,
69 ValueGetter,
70 WrapAlignment,
71 WrapCrossAlignment;
72export 'package:flutter/services.dart' show
73 AssetBundle;
74
75// Examples can assume:
76// class TestWidget extends StatelessWidget { const TestWidget({super.key}); @override Widget build(BuildContext context) => const Placeholder(); }
77// late WidgetTester tester;
78// late bool _visible;
79// class Sky extends CustomPainter { @override void paint(Canvas c, Size s) {} @override bool shouldRepaint(Sky s) => false; }
80// late BuildContext context;
81// String userAvatarUrl = '';
82
83// BIDIRECTIONAL TEXT SUPPORT
84
85/// An [InheritedElement] that has hundreds of dependencies but will
86/// infrequently change. This provides a performance tradeoff where building
87/// the [Widget]s is faster but performing updates is slower.
88///
89/// | | _UbiquitousInheritedElement | InheritedElement |
90/// |---------------------|------------------------------|------------------|
91/// | insert (best case) | O(1) | O(1) |
92/// | insert (worst case) | O(1) | O(n) |
93/// | search (best case) | O(n) | O(1) |
94/// | search (worst case) | O(n) | O(n) |
95///
96/// Insert happens when building the [Widget] tree, search happens when updating
97/// [Widget]s.
98class _UbiquitousInheritedElement extends InheritedElement {
99 /// Creates an element that uses the given widget as its configuration.
100 _UbiquitousInheritedElement(super.widget);
101
102 @override
103 void setDependencies(Element dependent, Object? value) {
104 // This is where the cost of [InheritedElement] is incurred during build
105 // time of the widget tree. Omitting this bookkeeping is where the
106 // performance savings come from.
107 assert(value == null);
108 }
109
110 @override
111 Object? getDependencies(Element dependent) {
112 return null;
113 }
114
115 @override
116 void notifyClients(InheritedWidget oldWidget) {
117 _recurseChildren(this, (Element element) {
118 if (element.doesDependOnInheritedElement(this)) {
119 notifyDependent(oldWidget, element);
120 }
121 });
122 }
123
124 static void _recurseChildren(Element element, ElementVisitor visitor) {
125 element.visitChildren((Element child) {
126 _recurseChildren(child, visitor);
127 });
128 visitor(element);
129 }
130}
131
132/// See also:
133///
134/// * [_UbiquitousInheritedElement], the [Element] for [_UbiquitousInheritedWidget].
135abstract class _UbiquitousInheritedWidget extends InheritedWidget {
136 const _UbiquitousInheritedWidget({super.key, required super.child});
137
138 @override
139 InheritedElement createElement() => _UbiquitousInheritedElement(this);
140}
141
142/// A widget that determines the ambient directionality of text and
143/// text-direction-sensitive render objects.
144///
145/// For example, [Padding] depends on the [Directionality] to resolve
146/// [EdgeInsetsDirectional] objects into absolute [EdgeInsets] objects.
147class Directionality extends _UbiquitousInheritedWidget {
148 /// Creates a widget that determines the directionality of text and
149 /// text-direction-sensitive render objects.
150 const Directionality({
151 super.key,
152 required this.textDirection,
153 required super.child,
154 });
155
156 /// The text direction for this subtree.
157 final TextDirection textDirection;
158
159 /// The text direction from the closest instance of this class that encloses
160 /// the given context.
161 ///
162 /// If there is no [Directionality] ancestor widget in the tree at the given
163 /// context, then this will throw a descriptive [FlutterError] in debug mode
164 /// and an exception in release mode.
165 ///
166 /// Typical usage is as follows:
167 ///
168 /// ```dart
169 /// TextDirection textDirection = Directionality.of(context);
170 /// ```
171 ///
172 /// See also:
173 ///
174 /// * [maybeOf], which will return null if no [Directionality] ancestor
175 /// widget is in the tree.
176 static TextDirection of(BuildContext context) {
177 assert(debugCheckHasDirectionality(context));
178 final Directionality widget = context.dependOnInheritedWidgetOfExactType<Directionality>()!;
179 return widget.textDirection;
180 }
181
182 /// The text direction from the closest instance of this class that encloses
183 /// the given context.
184 ///
185 /// If there is no [Directionality] ancestor widget in the tree at the given
186 /// context, then this will return null.
187 ///
188 /// Typical usage is as follows:
189 ///
190 /// ```dart
191 /// TextDirection? textDirection = Directionality.maybeOf(context);
192 /// ```
193 ///
194 /// See also:
195 ///
196 /// * [of], which will throw if no [Directionality] ancestor widget is in the
197 /// tree.
198 static TextDirection? maybeOf(BuildContext context) {
199 final Directionality? widget = context.dependOnInheritedWidgetOfExactType<Directionality>();
200 return widget?.textDirection;
201 }
202
203 @override
204 bool updateShouldNotify(Directionality oldWidget) => textDirection != oldWidget.textDirection;
205
206 @override
207 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
208 super.debugFillProperties(properties);
209 properties.add(EnumProperty<TextDirection>('textDirection', textDirection));
210 }
211}
212
213
214// PAINTING NODES
215
216/// A widget that makes its child partially transparent.
217///
218/// This class paints its child into an intermediate buffer and then blends the
219/// child back into the scene partially transparent.
220///
221/// For values of opacity other than 0.0 and 1.0, this class is relatively
222/// expensive because it requires painting the child into an intermediate
223/// buffer. For the value 0.0, the child is not painted at all. For the
224/// value 1.0, the child is painted immediately without an intermediate buffer.
225///
226/// The presence of the intermediate buffer which has a transparent background
227/// by default may cause some child widgets to behave differently. For example
228/// a [BackdropFilter] child will only be able to apply its filter to the content
229/// between this widget and the backdrop child and may require adjusting the
230/// [BackdropFilter.blendMode] property to produce the desired results.
231///
232/// {@youtube 560 315 https://www.youtube.com/watch?v=9hltevOHQBw}
233///
234/// {@tool snippet}
235///
236/// This example shows some [Text] when the `_visible` member field is true, and
237/// hides it when it is false:
238///
239/// ```dart
240/// Opacity(
241/// opacity: _visible ? 1.0 : 0.0,
242/// child: const Text("Now you see me, now you don't!"),
243/// )
244/// ```
245/// {@end-tool}
246///
247/// This is more efficient than adding and removing the child widget from the
248/// tree on demand.
249///
250/// ## Performance considerations for opacity animation
251///
252/// Animating an [Opacity] widget directly causes the widget (and possibly its
253/// subtree) to rebuild each frame, which is not very efficient. Consider using
254/// one of these alternative widgets instead:
255///
256/// * [AnimatedOpacity], which uses an animation internally to efficiently
257/// animate opacity.
258/// * [FadeTransition], which uses a provided animation to efficiently animate
259/// opacity.
260///
261/// ## Transparent image
262///
263/// If only a single [Image] or [Color] needs to be composited with an opacity
264/// between 0.0 and 1.0, it's much faster to directly use them without [Opacity]
265/// widgets.
266///
267/// For example, `Container(color: Color.fromRGBO(255, 0, 0, 0.5))` is much
268/// faster than `Opacity(opacity: 0.5, child: Container(color: Colors.red))`.
269///
270/// {@tool snippet}
271///
272/// The following example draws an [Image] with 0.5 opacity without using
273/// [Opacity]:
274///
275/// ```dart
276/// Image.network(
277/// 'https://raw.githubusercontent.com/flutter/assets-for-api-docs/master/packages/diagrams/assets/blend_mode_destination.jpeg',
278/// color: const Color.fromRGBO(255, 255, 255, 0.5),
279/// colorBlendMode: BlendMode.modulate
280/// )
281/// ```
282///
283/// {@end-tool}
284///
285/// Directly drawing an [Image] or [Color] with opacity is faster than using
286/// [Opacity] on top of them because [Opacity] could apply the opacity to a
287/// group of widgets and therefore a costly offscreen buffer will be used.
288/// Drawing content into the offscreen buffer may also trigger render target
289/// switches and such switching is particularly slow in older GPUs.
290///
291/// ## Hit testing
292///
293/// Setting the [opacity] to zero does not prevent hit testing from being applied
294/// to the descendants of the [Opacity] widget. This can be confusing for the
295/// user, who may not see anything, and may believe the area of the interface
296/// where the [Opacity] is hiding a widget to be non-interactive.
297///
298/// With certain widgets, such as [Flow], that compute their positions only when
299/// they are painted, this can actually lead to bugs (from unexpected geometry
300/// to exceptions), because those widgets are not painted by the [Opacity]
301/// widget at all when the [opacity] is zero.
302///
303/// To avoid such problems, it is generally a good idea to use an
304/// [IgnorePointer] widget when setting the [opacity] to zero. This prevents
305/// interactions with any children in the subtree.
306///
307/// See also:
308///
309/// * [Visibility], which can hide a child more efficiently (albeit less
310/// subtly, because it is either visible or hidden, rather than allowing
311/// fractional opacity values). Specifically, the [Visibility.maintain]
312/// constructor is equivalent to using an opacity widget with values of
313/// `0.0` or `1.0`.
314/// * [ShaderMask], which can apply more elaborate effects to its child.
315/// * [Transform], which applies an arbitrary transform to its child widget at
316/// paint time.
317/// * [SliverOpacity], the sliver version of this widget.
318class Opacity extends SingleChildRenderObjectWidget {
319 /// Creates a widget that makes its child partially transparent.
320 ///
321 /// The [opacity] argument must be between zero and one, inclusive.
322 const Opacity({
323 super.key,
324 required this.opacity,
325 this.alwaysIncludeSemantics = false,
326 super.child,
327 }) : assert(opacity >= 0.0 && opacity <= 1.0);
328
329 /// The fraction to scale the child's alpha value.
330 ///
331 /// An opacity of one is fully opaque. An opacity of zero is fully transparent
332 /// (i.e., invisible).
333 ///
334 /// Values one and zero are painted with a fast path. Other values require
335 /// painting the child into an intermediate buffer, which is expensive.
336 final double opacity;
337
338 /// Whether the semantic information of the children is always included.
339 ///
340 /// Defaults to false.
341 ///
342 /// When true, regardless of the opacity settings the child semantic
343 /// information is exposed as if the widget were fully visible. This is
344 /// useful in cases where labels may be hidden during animations that
345 /// would otherwise contribute relevant semantics.
346 final bool alwaysIncludeSemantics;
347
348 @override
349 RenderOpacity createRenderObject(BuildContext context) {
350 return RenderOpacity(
351 opacity: opacity,
352 alwaysIncludeSemantics: alwaysIncludeSemantics,
353 );
354 }
355
356 @override
357 void updateRenderObject(BuildContext context, RenderOpacity renderObject) {
358 renderObject
359 ..opacity = opacity
360 ..alwaysIncludeSemantics = alwaysIncludeSemantics;
361 }
362
363 @override
364 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
365 super.debugFillProperties(properties);
366 properties.add(DoubleProperty('opacity', opacity));
367 properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics'));
368 }
369}
370
371/// A widget that applies a mask generated by a [Shader] to its child.
372///
373/// For example, [ShaderMask] can be used to gradually fade out the edge
374/// of a child by using a [ui.Gradient.linear] mask.
375///
376/// {@youtube 560 315 https://www.youtube.com/watch?v=7sUL66pTQ7Q}
377///
378/// {@tool snippet}
379///
380/// This example makes the text look like it is on fire:
381///
382/// ```dart
383/// ShaderMask(
384/// shaderCallback: (Rect bounds) {
385/// return RadialGradient(
386/// center: Alignment.topLeft,
387/// radius: 1.0,
388/// colors: <Color>[Colors.yellow, Colors.deepOrange.shade900],
389/// tileMode: TileMode.mirror,
390/// ).createShader(bounds);
391/// },
392/// child: const Text(
393/// 'I’m burning the memories',
394/// style: TextStyle(color: Colors.white),
395/// ),
396/// )
397/// ```
398/// {@end-tool}
399///
400/// See also:
401///
402/// * [Opacity], which can apply a uniform alpha effect to its child.
403/// * [CustomPaint], which lets you draw directly on the canvas.
404/// * [DecoratedBox], for another approach at decorating child widgets.
405/// * [BackdropFilter], which applies an image filter to the background.
406class ShaderMask extends SingleChildRenderObjectWidget {
407 /// Creates a widget that applies a mask generated by a [Shader] to its child.
408 const ShaderMask({
409 super.key,
410 required this.shaderCallback,
411 this.blendMode = BlendMode.modulate,
412 super.child,
413 });
414
415 /// Called to create the [dart:ui.Shader] that generates the mask.
416 ///
417 /// The shader callback is called with the current size of the child so that
418 /// it can customize the shader to the size and location of the child.
419 ///
420 /// Typically this will use a [LinearGradient], [RadialGradient], or
421 /// [SweepGradient] to create the [dart:ui.Shader], though the
422 /// [dart:ui.ImageShader] class could also be used.
423 final ShaderCallback shaderCallback;
424
425 /// The [BlendMode] to use when applying the shader to the child.
426 ///
427 /// The default, [BlendMode.modulate], is useful for applying an alpha blend
428 /// to the child. Other blend modes can be used to create other effects.
429 final BlendMode blendMode;
430
431 @override
432 RenderShaderMask createRenderObject(BuildContext context) {
433 return RenderShaderMask(
434 shaderCallback: shaderCallback,
435 blendMode: blendMode,
436 );
437 }
438
439 @override
440 void updateRenderObject(BuildContext context, RenderShaderMask renderObject) {
441 renderObject
442 ..shaderCallback = shaderCallback
443 ..blendMode = blendMode;
444 }
445}
446
447/// A widget that applies a filter to the existing painted content and then
448/// paints [child].
449///
450/// The filter will be applied to all the area within its parent or ancestor
451/// widget's clip. If there's no clip, the filter will be applied to the full
452/// screen.
453///
454/// The results of the filter will be blended back into the background using
455/// the [blendMode] parameter.
456/// {@template flutter.widgets.BackdropFilter.blendMode}
457/// The only value for [blendMode] that is supported on all platforms is
458/// [BlendMode.srcOver] which works well for most scenes. But that value may
459/// produce surprising results when a parent of the [BackdropFilter] uses a
460/// temporary buffer, or save layer, as does an [Opacity] widget. In that
461/// situation, a value of [BlendMode.src] can produce more pleasing results,
462/// but at the cost of incompatibility with some platforms, most notably the
463/// html renderer for web applications.
464/// {@endtemplate}
465///
466/// {@youtube 560 315 https://www.youtube.com/watch?v=dYRs7Q1vfYI}
467///
468/// {@tool snippet}
469/// If the [BackdropFilter] needs to be applied to an area that exactly matches
470/// its child, wraps the [BackdropFilter] with a clip widget that clips exactly
471/// to that child.
472///
473/// ```dart
474/// Stack(
475/// fit: StackFit.expand,
476/// children: <Widget>[
477/// Text('0' * 10000),
478/// Center(
479/// child: ClipRect( // <-- clips to the 200x200 [Container] below
480/// child: BackdropFilter(
481/// filter: ui.ImageFilter.blur(
482/// sigmaX: 5.0,
483/// sigmaY: 5.0,
484/// ),
485/// child: Container(
486/// alignment: Alignment.center,
487/// width: 200.0,
488/// height: 200.0,
489/// child: const Text('Hello World'),
490/// ),
491/// ),
492/// ),
493/// ),
494/// ],
495/// )
496/// ```
497/// {@end-tool}
498///
499/// This effect is relatively expensive, especially if the filter is non-local,
500/// such as a blur.
501///
502/// If all you want to do is apply an [ImageFilter] to a single widget
503/// (as opposed to applying the filter to everything _beneath_ a widget), use
504/// [ImageFiltered] instead. For that scenario, [ImageFiltered] is both
505/// easier to use and less expensive than [BackdropFilter].
506///
507/// {@tool snippet}
508///
509/// This example shows how the common case of applying a [BackdropFilter] blur
510/// to a single sibling can be replaced with an [ImageFiltered] widget. This code
511/// is generally simpler and the performance will be improved dramatically for
512/// complex filters like blurs.
513///
514/// The implementation below is unnecessarily expensive.
515///
516/// ```dart
517/// Widget buildBackdrop() {
518/// return Stack(
519/// children: <Widget>[
520/// Positioned.fill(child: Image.asset('image.png')),
521/// Positioned.fill(
522/// child: BackdropFilter(
523/// filter: ui.ImageFilter.blur(sigmaX: 6, sigmaY: 6),
524/// ),
525/// ),
526/// ],
527/// );
528/// }
529/// ```
530/// {@end-tool}
531/// {@tool snippet}
532/// Instead consider the following approach which directly applies a blur
533/// to the child widget.
534///
535/// ```dart
536/// Widget buildFilter() {
537/// return ImageFiltered(
538/// imageFilter: ui.ImageFilter.blur(sigmaX: 6, sigmaY: 6),
539/// child: Image.asset('image.png'),
540/// );
541/// }
542/// ```
543///
544/// {@end-tool}
545///
546/// See also:
547///
548/// * [ImageFiltered], which applies an [ImageFilter] to its child.
549/// * [DecoratedBox], which draws a background under (or over) a widget.
550/// * [Opacity], which changes the opacity of the widget itself.
551/// * https://flutter.dev/go/ios-platformview-backdrop-filter-blur for details and restrictions when an iOS PlatformView needs to be blurred.
552class BackdropFilter extends SingleChildRenderObjectWidget {
553 /// Creates a backdrop filter.
554 ///
555 /// The [blendMode] argument will default to [BlendMode.srcOver] and must not be
556 /// null if provided.
557 const BackdropFilter({
558 super.key,
559 required this.filter,
560 super.child,
561 this.blendMode = BlendMode.srcOver,
562 });
563
564 /// The image filter to apply to the existing painted content before painting the child.
565 ///
566 /// For example, consider using [ImageFilter.blur] to create a backdrop
567 /// blur effect.
568 final ui.ImageFilter filter;
569
570 /// The blend mode to use to apply the filtered background content onto the background
571 /// surface.
572 ///
573 /// {@macro flutter.widgets.BackdropFilter.blendMode}
574 final BlendMode blendMode;
575
576 @override
577 RenderBackdropFilter createRenderObject(BuildContext context) {
578 return RenderBackdropFilter(filter: filter, blendMode: blendMode);
579 }
580
581 @override
582 void updateRenderObject(BuildContext context, RenderBackdropFilter renderObject) {
583 renderObject
584 ..filter = filter
585 ..blendMode = blendMode;
586 }
587}
588
589/// A widget that provides a canvas on which to draw during the paint phase.
590///
591/// When asked to paint, [CustomPaint] first asks its [painter] to paint on the
592/// current canvas, then it paints its child, and then, after painting its
593/// child, it asks its [foregroundPainter] to paint. The coordinate system of the
594/// canvas matches the coordinate system of the [CustomPaint] object. The
595/// painters are expected to paint within a rectangle starting at the origin and
596/// encompassing a region of the given size. (If the painters paint outside
597/// those bounds, there might be insufficient memory allocated to rasterize the
598/// painting commands and the resulting behavior is undefined.) To enforce
599/// painting within those bounds, consider wrapping this [CustomPaint] with a
600/// [ClipRect] widget.
601///
602/// Painters are implemented by subclassing [CustomPainter].
603///
604/// {@youtube 560 315 https://www.youtube.com/watch?v=kp14Y4uHpHs}
605///
606/// Because custom paint calls its painters during paint, you cannot call
607/// `setState` or `markNeedsLayout` during the callback (the layout for this
608/// frame has already happened).
609///
610/// Custom painters normally size themselves to their [child]. If they do not
611/// have a child, they attempt to size themselves to the specified [size], which
612/// defaults to [Size.zero]. The parent [may enforce constraints on this
613/// size](https://docs.flutter.dev/ui/layout/constraints).
614///
615/// The [isComplex] and [willChange] properties are hints to the compositor's
616/// raster cache.
617///
618/// {@tool snippet}
619///
620/// This example shows how the sample custom painter shown at [CustomPainter]
621/// could be used in a [CustomPaint] widget to display a background to some
622/// text.
623///
624/// ```dart
625/// CustomPaint(
626/// painter: Sky(),
627/// child: const Center(
628/// child: Text(
629/// 'Once upon a time...',
630/// style: TextStyle(
631/// fontSize: 40.0,
632/// fontWeight: FontWeight.w900,
633/// color: Color(0xFFFFFFFF),
634/// ),
635/// ),
636/// ),
637/// )
638/// ```
639/// {@end-tool}
640///
641/// See also:
642///
643/// * [CustomPainter], the class to extend when creating custom painters.
644/// * [Canvas], the class that a custom painter uses to paint.
645class CustomPaint extends SingleChildRenderObjectWidget {
646 /// Creates a widget that delegates its painting.
647 const CustomPaint({
648 super.key,
649 this.painter,
650 this.foregroundPainter,
651 this.size = Size.zero,
652 this.isComplex = false,
653 this.willChange = false,
654 super.child,
655 }) : assert(painter != null || foregroundPainter != null || (!isComplex && !willChange));
656
657 /// The painter that paints before the children.
658 final CustomPainter? painter;
659
660 /// The painter that paints after the children.
661 final CustomPainter? foregroundPainter;
662
663 /// The size that this [CustomPaint] should aim for, given the layout
664 /// constraints, if there is no child.
665 ///
666 /// Defaults to [Size.zero].
667 ///
668 /// If there's a child, this is ignored, and the size of the child is used
669 /// instead.
670 final Size size;
671
672 /// Whether the painting is complex enough to benefit from caching.
673 ///
674 /// The compositor contains a raster cache that holds bitmaps of layers in
675 /// order to avoid the cost of repeatedly rendering those layers on each
676 /// frame. If this flag is not set, then the compositor will apply its own
677 /// heuristics to decide whether the layer containing this widget is complex
678 /// enough to benefit from caching.
679 ///
680 /// This flag can't be set to true if both [painter] and [foregroundPainter]
681 /// are null because this flag will be ignored in such case.
682 final bool isComplex;
683
684 /// Whether the raster cache should be told that this painting is likely
685 /// to change in the next frame.
686 ///
687 /// This hint tells the compositor not to cache the layer containing this
688 /// widget because the cache will not be used in the future. If this hint is
689 /// not set, the compositor will apply its own heuristics to decide whether
690 /// the layer is likely to be reused in the future.
691 ///
692 /// This flag can't be set to true if both [painter] and [foregroundPainter]
693 /// are null because this flag will be ignored in such case.
694 final bool willChange;
695
696 @override
697 RenderCustomPaint createRenderObject(BuildContext context) {
698 return RenderCustomPaint(
699 painter: painter,
700 foregroundPainter: foregroundPainter,
701 preferredSize: size,
702 isComplex: isComplex,
703 willChange: willChange,
704 );
705 }
706
707 @override
708 void updateRenderObject(BuildContext context, RenderCustomPaint renderObject) {
709 renderObject
710 ..painter = painter
711 ..foregroundPainter = foregroundPainter
712 ..preferredSize = size
713 ..isComplex = isComplex
714 ..willChange = willChange;
715 }
716
717 @override
718 void didUnmountRenderObject(RenderCustomPaint renderObject) {
719 renderObject
720 ..painter = null
721 ..foregroundPainter = null;
722 }
723}
724
725/// A widget that clips its child using a rectangle.
726///
727/// By default, [ClipRect] prevents its child from painting outside its
728/// bounds, but the size and location of the clip rect can be customized using a
729/// custom [clipper].
730///
731/// [ClipRect] is commonly used with these widgets, which commonly paint outside
732/// their bounds:
733///
734/// * [CustomPaint]
735/// * [CustomSingleChildLayout]
736/// * [CustomMultiChildLayout]
737/// * [Align] and [Center] (e.g., if [Align.widthFactor] or
738/// [Align.heightFactor] is less than 1.0).
739/// * [OverflowBox]
740/// * [SizedOverflowBox]
741///
742/// {@tool snippet}
743///
744/// For example, by combining a [ClipRect] with an [Align], one can show just
745/// the top half of an [Image]:
746///
747/// ```dart
748/// ClipRect(
749/// child: Align(
750/// alignment: Alignment.topCenter,
751/// heightFactor: 0.5,
752/// child: Image.network(userAvatarUrl),
753/// ),
754/// )
755/// ```
756/// {@end-tool}
757///
758/// See also:
759///
760/// * [CustomClipper], for information about creating custom clips.
761/// * [ClipRRect], for a clip with rounded corners.
762/// * [ClipOval], for an elliptical clip.
763/// * [ClipPath], for an arbitrarily shaped clip.
764class ClipRect extends SingleChildRenderObjectWidget {
765 /// Creates a rectangular clip.
766 ///
767 /// If [clipper] is null, the clip will match the layout size and position of
768 /// the child.
769 ///
770 /// If [clipBehavior] is [Clip.none], no clipping will be applied.
771 const ClipRect({
772 super.key,
773 this.clipper,
774 this.clipBehavior = Clip.hardEdge,
775 super.child,
776 });
777
778 /// If non-null, determines which clip to use.
779 final CustomClipper<Rect>? clipper;
780
781 /// {@macro flutter.rendering.ClipRectLayer.clipBehavior}
782 ///
783 /// Defaults to [Clip.hardEdge].
784 final Clip clipBehavior;
785
786 @override
787 RenderClipRect createRenderObject(BuildContext context) {
788 return RenderClipRect(clipper: clipper, clipBehavior: clipBehavior);
789 }
790
791 @override
792 void updateRenderObject(BuildContext context, RenderClipRect renderObject) {
793 renderObject
794 ..clipper = clipper
795 ..clipBehavior = clipBehavior;
796 }
797
798 @override
799 void didUnmountRenderObject(RenderClipRect renderObject) {
800 renderObject.clipper = null;
801 }
802
803 @override
804 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
805 super.debugFillProperties(properties);
806 properties.add(DiagnosticsProperty<CustomClipper<Rect>>('clipper', clipper, defaultValue: null));
807 }
808}
809
810/// A widget that clips its child using a rounded rectangle.
811///
812/// By default, [ClipRRect] uses its own bounds as the base rectangle for the
813/// clip, but the size and location of the clip can be customized using a custom
814/// [clipper].
815///
816/// {@youtube 560 315 https://www.youtube.com/watch?v=eI43jkQkrvs}
817///
818/// {@tool dartpad}
819/// This example shows various [ClipRRect]s applied to containers.
820///
821/// ** See code in examples/api/lib/widgets/basic/clip_rrect.0.dart **
822/// {@end-tool}
823///
824/// ## Troubleshooting
825///
826/// ### Why doesn't my [ClipRRect] child have rounded corners?
827///
828/// When a [ClipRRect] is bigger than the child it contains, its rounded corners
829/// could be drawn in unexpected positions. Make sure that [ClipRRect] and its child
830/// have the same bounds (by shrinking the [ClipRRect] with a [FittedBox] or by
831/// growing the child).
832///
833/// {@tool dartpad}
834/// This example shows a [ClipRRect] that adds round corners to an image.
835///
836/// ** See code in examples/api/lib/widgets/basic/clip_rrect.1.dart **
837/// {@end-tool}
838///
839/// See also:
840///
841/// * [CustomClipper], for information about creating custom clips.
842/// * [ClipRect], for more efficient clips without rounded corners.
843/// * [ClipOval], for an elliptical clip.
844/// * [ClipPath], for an arbitrarily shaped clip.
845class ClipRRect extends SingleChildRenderObjectWidget {
846 /// Creates a rounded-rectangular clip.
847 ///
848 /// The [borderRadius] defaults to [BorderRadius.zero], i.e. a rectangle with
849 /// right-angled corners.
850 ///
851 /// If [clipper] is non-null, then [borderRadius] is ignored.
852 ///
853 /// If [clipBehavior] is [Clip.none], no clipping will be applied.
854 const ClipRRect({
855 super.key,
856 this.borderRadius = BorderRadius.zero,
857 this.clipper,
858 this.clipBehavior = Clip.antiAlias,
859 super.child,
860 });
861
862 /// The border radius of the rounded corners.
863 ///
864 /// Values are clamped so that horizontal and vertical radii sums do not
865 /// exceed width/height.
866 ///
867 /// This value is ignored if [clipper] is non-null.
868 final BorderRadiusGeometry borderRadius;
869
870 /// If non-null, determines which clip to use.
871 final CustomClipper<RRect>? clipper;
872
873 /// {@macro flutter.rendering.ClipRectLayer.clipBehavior}
874 ///
875 /// Defaults to [Clip.antiAlias].
876 final Clip clipBehavior;
877
878 @override
879 RenderClipRRect createRenderObject(BuildContext context) {
880 return RenderClipRRect(
881 borderRadius: borderRadius,
882 clipper: clipper,
883 clipBehavior: clipBehavior,
884 textDirection: Directionality.maybeOf(context),
885 );
886 }
887
888 @override
889 void updateRenderObject(BuildContext context, RenderClipRRect renderObject) {
890 renderObject
891 ..borderRadius = borderRadius
892 ..clipBehavior = clipBehavior
893 ..clipper = clipper
894 ..textDirection = Directionality.maybeOf(context);
895 }
896
897 @override
898 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
899 super.debugFillProperties(properties);
900 properties.add(DiagnosticsProperty<BorderRadiusGeometry>('borderRadius', borderRadius, showName: false, defaultValue: null));
901 properties.add(DiagnosticsProperty<CustomClipper<RRect>>('clipper', clipper, defaultValue: null));
902 }
903}
904
905/// A widget that clips its child using an oval.
906///
907/// {@youtube 560 315 https://www.youtube.com/watch?v=vzWWDO6whIM}
908///
909/// By default, inscribes an axis-aligned oval into its layout dimensions and
910/// prevents its child from painting outside that oval, but the size and
911/// location of the clip oval can be customized using a custom [clipper].
912///
913/// See also:
914///
915/// * [CustomClipper], for information about creating custom clips.
916/// * [ClipRect], for more efficient clips without rounded corners.
917/// * [ClipRRect], for a clip with rounded corners.
918/// * [ClipPath], for an arbitrarily shaped clip.
919class ClipOval extends SingleChildRenderObjectWidget {
920 /// Creates an oval-shaped clip.
921 ///
922 /// If [clipper] is null, the oval will be inscribed into the layout size and
923 /// position of the child.
924 ///
925 /// If [clipBehavior] is [Clip.none], no clipping will be applied.
926 const ClipOval({
927 super.key,
928 this.clipper,
929 this.clipBehavior = Clip.antiAlias,
930 super.child,
931 });
932
933 /// If non-null, determines which clip to use.
934 ///
935 /// The delegate returns a rectangle that describes the axis-aligned
936 /// bounding box of the oval. The oval's axes will themselves also
937 /// be axis-aligned.
938 ///
939 /// If the [clipper] delegate is null, then the oval uses the
940 /// widget's bounding box (the layout dimensions of the render
941 /// object) instead.
942 final CustomClipper<Rect>? clipper;
943
944 /// {@macro flutter.rendering.ClipRectLayer.clipBehavior}
945 ///
946 /// Defaults to [Clip.antiAlias].
947 final Clip clipBehavior;
948
949 @override
950 RenderClipOval createRenderObject(BuildContext context) {
951 return RenderClipOval(clipper: clipper, clipBehavior: clipBehavior);
952 }
953
954 @override
955 void updateRenderObject(BuildContext context, RenderClipOval renderObject) {
956 renderObject
957 ..clipper = clipper
958 ..clipBehavior = clipBehavior;
959 }
960
961 @override
962 void didUnmountRenderObject(RenderClipOval renderObject) {
963 renderObject.clipper = null;
964 }
965
966 @override
967 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
968 super.debugFillProperties(properties);
969 properties.add(DiagnosticsProperty<CustomClipper<Rect>>('clipper', clipper, defaultValue: null));
970 }
971}
972
973/// A widget that clips its child using a path.
974///
975/// Calls a callback on a delegate whenever the widget is to be
976/// painted. The callback returns a path and the widget prevents the
977/// child from painting outside the path.
978///
979/// {@youtube 560 315 https://www.youtube.com/watch?v=oAUebVIb-7s}
980///
981/// Clipping to a path is expensive. Certain shapes have more
982/// optimized widgets:
983///
984/// * To clip to a rectangle, consider [ClipRect].
985/// * To clip to an oval or circle, consider [ClipOval].
986/// * To clip to a rounded rectangle, consider [ClipRRect].
987///
988/// To clip to a particular [ShapeBorder], consider using either the
989/// [ClipPath.shape] static method or the [ShapeBorderClipper] custom clipper
990/// class.
991class ClipPath extends SingleChildRenderObjectWidget {
992 /// Creates a path clip.
993 ///
994 /// If [clipper] is null, the clip will be a rectangle that matches the layout
995 /// size and location of the child. However, rather than use this default,
996 /// consider using a [ClipRect], which can achieve the same effect more
997 /// efficiently.
998 ///
999 /// If [clipBehavior] is [Clip.none], no clipping will be applied.
1000 const ClipPath({
1001 super.key,
1002 this.clipper,
1003 this.clipBehavior = Clip.antiAlias,
1004 super.child,
1005 });
1006
1007 /// Creates a shape clip.
1008 ///
1009 /// Uses a [ShapeBorderClipper] to configure the [ClipPath] to clip to the
1010 /// given [ShapeBorder].
1011 static Widget shape({
1012 Key? key,
1013 required ShapeBorder shape,
1014 Clip clipBehavior = Clip.antiAlias,
1015 Widget? child,
1016 }) {
1017 return Builder(
1018 key: key,
1019 builder: (BuildContext context) {
1020 return ClipPath(
1021 clipper: ShapeBorderClipper(
1022 shape: shape,
1023 textDirection: Directionality.maybeOf(context),
1024 ),
1025 clipBehavior: clipBehavior,
1026 child: child,
1027 );
1028 },
1029 );
1030 }
1031
1032 /// If non-null, determines which clip to use.
1033 ///
1034 /// The default clip, which is used if this property is null, is the
1035 /// bounding box rectangle of the widget. [ClipRect] is a more
1036 /// efficient way of obtaining that effect.
1037 final CustomClipper<Path>? clipper;
1038
1039 /// {@macro flutter.rendering.ClipRectLayer.clipBehavior}
1040 ///
1041 /// Defaults to [Clip.antiAlias].
1042 final Clip clipBehavior;
1043
1044 @override
1045 RenderClipPath createRenderObject(BuildContext context) {
1046 return RenderClipPath(clipper: clipper, clipBehavior: clipBehavior);
1047 }
1048
1049 @override
1050 void updateRenderObject(BuildContext context, RenderClipPath renderObject) {
1051 renderObject
1052 ..clipper = clipper
1053 ..clipBehavior = clipBehavior;
1054 }
1055
1056 @override
1057 void didUnmountRenderObject(RenderClipPath renderObject) {
1058 renderObject.clipper = null;
1059 }
1060
1061 @override
1062 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1063 super.debugFillProperties(properties);
1064 properties.add(DiagnosticsProperty<CustomClipper<Path>>('clipper', clipper, defaultValue: null));
1065 }
1066}
1067
1068/// A widget representing a physical layer that clips its children to a shape.
1069///
1070/// {@youtube 560 315 https://www.youtube.com/watch?v=XgUOSS30OQk}
1071///
1072/// Physical layers cast shadows based on an [elevation] which is nominally in
1073/// logical pixels, coming vertically out of the rendering surface.
1074///
1075/// For shapes that cannot be expressed as a rectangle with rounded corners use
1076/// [PhysicalShape].
1077///
1078/// See also:
1079///
1080/// * [AnimatedPhysicalModel], which animates property changes smoothly over
1081/// a given duration.
1082/// * [DecoratedBox], which can apply more arbitrary shadow effects.
1083/// * [ClipRect], which applies a clip to its child.
1084class PhysicalModel extends SingleChildRenderObjectWidget {
1085 /// Creates a physical model with a rounded-rectangular clip.
1086 ///
1087 /// The [color] is required; physical things have a color.
1088 ///
1089 /// The [shape], [elevation], [color], [clipBehavior], and [shadowColor] must
1090 /// not be null. Additionally, the [elevation] must be non-negative.
1091 const PhysicalModel({
1092 super.key,
1093 this.shape = BoxShape.rectangle,
1094 this.clipBehavior = Clip.none,
1095 this.borderRadius,
1096 this.elevation = 0.0,
1097 required this.color,
1098 this.shadowColor = const Color(0xFF000000),
1099 super.child,
1100 }) : assert(elevation >= 0.0);
1101
1102 /// The type of shape.
1103 final BoxShape shape;
1104
1105 /// {@macro flutter.material.Material.clipBehavior}
1106 ///
1107 /// Defaults to [Clip.none].
1108 final Clip clipBehavior;
1109
1110 /// The border radius of the rounded corners.
1111 ///
1112 /// Values are clamped so that horizontal and vertical radii sums do not
1113 /// exceed width/height.
1114 ///
1115 /// This is ignored if the [shape] is not [BoxShape.rectangle].
1116 final BorderRadius? borderRadius;
1117
1118 /// The z-coordinate relative to the parent at which to place this physical
1119 /// object.
1120 ///
1121 /// The value is non-negative.
1122 final double elevation;
1123
1124 /// The background color.
1125 final Color color;
1126
1127 /// The shadow color.
1128 final Color shadowColor;
1129
1130 @override
1131 RenderPhysicalModel createRenderObject(BuildContext context) {
1132 return RenderPhysicalModel(
1133 shape: shape,
1134 clipBehavior: clipBehavior,
1135 borderRadius: borderRadius,
1136 elevation: elevation,
1137 color: color,
1138 shadowColor: shadowColor,
1139 );
1140 }
1141
1142 @override
1143 void updateRenderObject(BuildContext context, RenderPhysicalModel renderObject) {
1144 renderObject
1145 ..shape = shape
1146 ..clipBehavior = clipBehavior
1147 ..borderRadius = borderRadius
1148 ..elevation = elevation
1149 ..color = color
1150 ..shadowColor = shadowColor;
1151 }
1152
1153 @override
1154 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1155 super.debugFillProperties(properties);
1156 properties.add(EnumProperty<BoxShape>('shape', shape));
1157 properties.add(DiagnosticsProperty<BorderRadius>('borderRadius', borderRadius));
1158 properties.add(DoubleProperty('elevation', elevation));
1159 properties.add(ColorProperty('color', color));
1160 properties.add(ColorProperty('shadowColor', shadowColor));
1161 }
1162}
1163
1164/// A widget representing a physical layer that clips its children to a path.
1165///
1166/// Physical layers cast shadows based on an [elevation] which is nominally in
1167/// logical pixels, coming vertically out of the rendering surface.
1168///
1169/// [PhysicalModel] does the same but only supports shapes that can be expressed
1170/// as rectangles with rounded corners.
1171///
1172/// {@tool dartpad}
1173/// This example shows how to use a [PhysicalShape] on a centered [SizedBox]
1174/// to clip it to a rounded rectangle using a [ShapeBorderClipper] and give it
1175/// an orange color along with a shadow.
1176///
1177/// ** See code in examples/api/lib/widgets/basic/physical_shape.0.dart **
1178/// {@end-tool}
1179///
1180/// See also:
1181///
1182/// * [ShapeBorderClipper], which converts a [ShapeBorder] to a [CustomClipper], as
1183/// needed by this widget.
1184class PhysicalShape extends SingleChildRenderObjectWidget {
1185 /// Creates a physical model with an arbitrary shape clip.
1186 ///
1187 /// The [color] is required; physical things have a color.
1188 ///
1189 /// The [elevation] must be non-negative.
1190 const PhysicalShape({
1191 super.key,
1192 required this.clipper,
1193 this.clipBehavior = Clip.none,
1194 this.elevation = 0.0,
1195 required this.color,
1196 this.shadowColor = const Color(0xFF000000),
1197 super.child,
1198 }) : assert(elevation >= 0.0);
1199
1200 /// Determines which clip to use.
1201 ///
1202 /// If the path in question is expressed as a [ShapeBorder] subclass,
1203 /// consider using the [ShapeBorderClipper] delegate class to adapt the
1204 /// shape for use with this widget.
1205 final CustomClipper<Path> clipper;
1206
1207 /// {@macro flutter.material.Material.clipBehavior}
1208 ///
1209 /// Defaults to [Clip.none].
1210 final Clip clipBehavior;
1211
1212 /// The z-coordinate relative to the parent at which to place this physical
1213 /// object.
1214 ///
1215 /// The value is non-negative.
1216 final double elevation;
1217
1218 /// The background color.
1219 final Color color;
1220
1221 /// When elevation is non zero the color to use for the shadow color.
1222 final Color shadowColor;
1223
1224 @override
1225 RenderPhysicalShape createRenderObject(BuildContext context) {
1226 return RenderPhysicalShape(
1227 clipper: clipper,
1228 clipBehavior: clipBehavior,
1229 elevation: elevation,
1230 color: color,
1231 shadowColor: shadowColor,
1232 );
1233 }
1234
1235 @override
1236 void updateRenderObject(BuildContext context, RenderPhysicalShape renderObject) {
1237 renderObject
1238 ..clipper = clipper
1239 ..clipBehavior = clipBehavior
1240 ..elevation = elevation
1241 ..color = color
1242 ..shadowColor = shadowColor;
1243 }
1244
1245 @override
1246 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1247 super.debugFillProperties(properties);
1248 properties.add(DiagnosticsProperty<CustomClipper<Path>>('clipper', clipper));
1249 properties.add(DoubleProperty('elevation', elevation));
1250 properties.add(ColorProperty('color', color));
1251 properties.add(ColorProperty('shadowColor', shadowColor));
1252 }
1253}
1254
1255
1256// POSITIONING AND SIZING NODES
1257
1258/// A widget that applies a transformation before painting its child.
1259///
1260/// Unlike [RotatedBox], which applies a rotation prior to layout, this object
1261/// applies its transformation just prior to painting, which means the
1262/// transformation is not taken into account when calculating how much space
1263/// this widget's child (and thus this widget) consumes.
1264///
1265/// {@youtube 560 315 https://www.youtube.com/watch?v=9z_YNlRlWfA}
1266///
1267/// {@tool snippet}
1268///
1269/// This example rotates and skews an orange box containing text, keeping the
1270/// top right corner pinned to its original position.
1271///
1272/// ```dart
1273/// ColoredBox(
1274/// color: Colors.black,
1275/// child: Transform(
1276/// alignment: Alignment.topRight,
1277/// transform: Matrix4.skewY(0.3)..rotateZ(-math.pi / 12.0),
1278/// child: Container(
1279/// padding: const EdgeInsets.all(8.0),
1280/// color: const Color(0xFFE8581C),
1281/// child: const Text('Apartment for rent!'),
1282/// ),
1283/// ),
1284/// )
1285/// ```
1286/// {@end-tool}
1287///
1288/// See also:
1289///
1290/// * [RotatedBox], which rotates the child widget during layout, not just
1291/// during painting.
1292/// * [FractionalTranslation], which applies a translation to the child
1293/// that is relative to the child's size.
1294/// * [FittedBox], which sizes and positions its child widget to fit the parent
1295/// according to a given [BoxFit] discipline.
1296/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
1297class Transform extends SingleChildRenderObjectWidget {
1298 /// Creates a widget that transforms its child.
1299 const Transform({
1300 super.key,
1301 required this.transform,
1302 this.origin,
1303 this.alignment,
1304 this.transformHitTests = true,
1305 this.filterQuality,
1306 super.child,
1307 });
1308
1309 /// Creates a widget that transforms its child using a rotation around the
1310 /// center.
1311 ///
1312 /// The `angle` argument gives the rotation in clockwise radians.
1313 ///
1314 /// {@tool snippet}
1315 ///
1316 /// This example rotates an orange box containing text around its center by
1317 /// fifteen degrees.
1318 ///
1319 /// ```dart
1320 /// Transform.rotate(
1321 /// angle: -math.pi / 12.0,
1322 /// child: Container(
1323 /// padding: const EdgeInsets.all(8.0),
1324 /// color: const Color(0xFFE8581C),
1325 /// child: const Text('Apartment for rent!'),
1326 /// ),
1327 /// )
1328 /// ```
1329 /// {@end-tool}
1330 ///
1331 /// See also:
1332 ///
1333 /// * [RotationTransition], which animates changes in rotation smoothly
1334 /// over a given duration.
1335 Transform.rotate({
1336 super.key,
1337 required double angle,
1338 this.origin,
1339 this.alignment = Alignment.center,
1340 this.transformHitTests = true,
1341 this.filterQuality,
1342 super.child,
1343 }) : transform = _computeRotation(angle);
1344
1345 /// Creates a widget that transforms its child using a translation.
1346 ///
1347 /// The `offset` argument specifies the translation.
1348 ///
1349 /// {@tool snippet}
1350 ///
1351 /// This example shifts the silver-colored child down by fifteen pixels.
1352 ///
1353 /// ```dart
1354 /// Transform.translate(
1355 /// offset: const Offset(0.0, 15.0),
1356 /// child: Container(
1357 /// padding: const EdgeInsets.all(8.0),
1358 /// color: const Color(0xFF7F7F7F),
1359 /// child: const Text('Quarter'),
1360 /// ),
1361 /// )
1362 /// ```
1363 /// {@end-tool}
1364 Transform.translate({
1365 super.key,
1366 required Offset offset,
1367 this.transformHitTests = true,
1368 this.filterQuality,
1369 super.child,
1370 }) : transform = Matrix4.translationValues(offset.dx, offset.dy, 0.0),
1371 origin = null,
1372 alignment = null;
1373
1374 /// Creates a widget that scales its child along the 2D plane.
1375 ///
1376 /// The `scaleX` argument provides the scalar by which to multiply the `x`
1377 /// axis, and the `scaleY` argument provides the scalar by which to multiply
1378 /// the `y` axis. Either may be omitted, in which case the scaling factor for
1379 /// that axis defaults to 1.0.
1380 ///
1381 /// For convenience, to scale the child uniformly, instead of providing
1382 /// `scaleX` and `scaleY`, the `scale` parameter may be used.
1383 ///
1384 /// At least one of `scale`, `scaleX`, and `scaleY` must be non-null. If
1385 /// `scale` is provided, the other two must be null; similarly, if it is not
1386 /// provided, one of the other two must be provided.
1387 ///
1388 /// The [alignment] controls the origin of the scale; by default, this is the
1389 /// center of the box.
1390 ///
1391 /// {@tool snippet}
1392 ///
1393 /// This example shrinks an orange box containing text such that each
1394 /// dimension is half the size it would otherwise be.
1395 ///
1396 /// ```dart
1397 /// Transform.scale(
1398 /// scale: 0.5,
1399 /// child: Container(
1400 /// padding: const EdgeInsets.all(8.0),
1401 /// color: const Color(0xFFE8581C),
1402 /// child: const Text('Bad Idea Bears'),
1403 /// ),
1404 /// )
1405 /// ```
1406 /// {@end-tool}
1407 ///
1408 /// See also:
1409 ///
1410 /// * [ScaleTransition], which animates changes in scale smoothly over a given
1411 /// duration.
1412 Transform.scale({
1413 super.key,
1414 double? scale,
1415 double? scaleX,
1416 double? scaleY,
1417 this.origin,
1418 this.alignment = Alignment.center,
1419 this.transformHitTests = true,
1420 this.filterQuality,
1421 super.child,
1422 }) : assert(!(scale == null && scaleX == null && scaleY == null), "At least one of 'scale', 'scaleX' and 'scaleY' is required to be non-null"),
1423 assert(scale == null || (scaleX == null && scaleY == null), "If 'scale' is non-null then 'scaleX' and 'scaleY' must be left null"),
1424 transform = Matrix4.diagonal3Values(scale ?? scaleX ?? 1.0, scale ?? scaleY ?? 1.0, 1.0);
1425
1426 /// Creates a widget that mirrors its child about the widget's center point.
1427 ///
1428 /// If `flipX` is true, the child widget will be flipped horizontally. Defaults to false.
1429 ///
1430 /// If `flipY` is true, the child widget will be flipped vertically. Defaults to false.
1431 ///
1432 /// If both are true, the child widget will be flipped both vertically and horizontally, equivalent to a 180 degree rotation.
1433 ///
1434 /// {@tool snippet}
1435 ///
1436 /// This example flips the text horizontally.
1437 ///
1438 /// ```dart
1439 /// Transform.flip(
1440 /// flipX: true,
1441 /// child: const Text('Horizontal Flip'),
1442 /// )
1443 /// ```
1444 /// {@end-tool}
1445 Transform.flip({
1446 super.key,
1447 bool flipX = false,
1448 bool flipY = false,
1449 this.origin,
1450 this.transformHitTests = true,
1451 this.filterQuality,
1452 super.child,
1453 }) : alignment = Alignment.center,
1454 transform = Matrix4.diagonal3Values(flipX ? -1.0 : 1.0, flipY ? -1.0 : 1.0, 1.0);
1455
1456 // Computes a rotation matrix for an angle in radians, attempting to keep rotations
1457 // at integral values for angles of 0, π/2, π, 3π/2.
1458 static Matrix4 _computeRotation(double radians) {
1459 assert(radians.isFinite, 'Cannot compute the rotation matrix for a non-finite angle: $radians');
1460 if (radians == 0.0) {
1461 return Matrix4.identity();
1462 }
1463 final double sin = math.sin(radians);
1464 if (sin == 1.0) {
1465 return _createZRotation(1.0, 0.0);
1466 }
1467 if (sin == -1.0) {
1468 return _createZRotation(-1.0, 0.0);
1469 }
1470 final double cos = math.cos(radians);
1471 if (cos == -1.0) {
1472 return _createZRotation(0.0, -1.0);
1473 }
1474 return _createZRotation(sin, cos);
1475 }
1476
1477 static Matrix4 _createZRotation(double sin, double cos) {
1478 final Matrix4 result = Matrix4.zero();
1479 result.storage[0] = cos;
1480 result.storage[1] = sin;
1481 result.storage[4] = -sin;
1482 result.storage[5] = cos;
1483 result.storage[10] = 1.0;
1484 result.storage[15] = 1.0;
1485 return result;
1486 }
1487
1488 /// The matrix to transform the child by during painting.
1489 final Matrix4 transform;
1490
1491 /// The origin of the coordinate system (relative to the upper left corner of
1492 /// this render object) in which to apply the matrix.
1493 ///
1494 /// Setting an origin is equivalent to conjugating the transform matrix by a
1495 /// translation. This property is provided just for convenience.
1496 final Offset? origin;
1497
1498 /// The alignment of the origin, relative to the size of the box.
1499 ///
1500 /// This is equivalent to setting an origin based on the size of the box.
1501 /// If it is specified at the same time as the [origin], both are applied.
1502 ///
1503 /// An [AlignmentDirectional.centerStart] value is the same as an [Alignment]
1504 /// whose [Alignment.x] value is `-1.0` if [Directionality.of] returns
1505 /// [TextDirection.ltr], and `1.0` if [Directionality.of] returns
1506 /// [TextDirection.rtl]. Similarly [AlignmentDirectional.centerEnd] is the
1507 /// same as an [Alignment] whose [Alignment.x] value is `1.0` if
1508 /// [Directionality.of] returns [TextDirection.ltr], and `-1.0` if
1509 /// [Directionality.of] returns [TextDirection.rtl].
1510 final AlignmentGeometry? alignment;
1511
1512 /// Whether to apply the transformation when performing hit tests.
1513 final bool transformHitTests;
1514
1515 /// The filter quality with which to apply the transform as a bitmap operation.
1516 ///
1517 /// {@template flutter.widgets.Transform.optional.FilterQuality}
1518 /// The transform will be applied by re-rendering the child if [filterQuality] is null,
1519 /// otherwise it controls the quality of an [ImageFilter.matrix] applied to a bitmap
1520 /// rendering of the child.
1521 /// {@endtemplate}
1522 final FilterQuality? filterQuality;
1523
1524 @override
1525 RenderTransform createRenderObject(BuildContext context) {
1526 return RenderTransform(
1527 transform: transform,
1528 origin: origin,
1529 alignment: alignment,
1530 textDirection: Directionality.maybeOf(context),
1531 transformHitTests: transformHitTests,
1532 filterQuality: filterQuality,
1533 );
1534 }
1535
1536 @override
1537 void updateRenderObject(BuildContext context, RenderTransform renderObject) {
1538 renderObject
1539 ..transform = transform
1540 ..origin = origin
1541 ..alignment = alignment
1542 ..textDirection = Directionality.maybeOf(context)
1543 ..transformHitTests = transformHitTests
1544 ..filterQuality = filterQuality;
1545 }
1546}
1547
1548/// A widget that can be targeted by a [CompositedTransformFollower].
1549///
1550/// When this widget is composited during the compositing phase (which comes
1551/// after the paint phase, as described in [WidgetsBinding.drawFrame]), it
1552/// updates the [link] object so that any [CompositedTransformFollower] widgets
1553/// that are subsequently composited in the same frame and were given the same
1554/// [LayerLink] can position themselves at the same screen location.
1555///
1556/// A single [CompositedTransformTarget] can be followed by multiple
1557/// [CompositedTransformFollower] widgets.
1558///
1559/// The [CompositedTransformTarget] must come earlier in the paint order than
1560/// any linked [CompositedTransformFollower]s.
1561///
1562/// See also:
1563///
1564/// * [CompositedTransformFollower], the widget that can target this one.
1565/// * [LeaderLayer], the layer that implements this widget's logic.
1566class CompositedTransformTarget extends SingleChildRenderObjectWidget {
1567 /// Creates a composited transform target widget.
1568 ///
1569 /// The [link] property must not be currently used by any other
1570 /// [CompositedTransformTarget] object that is in the tree.
1571 const CompositedTransformTarget({
1572 super.key,
1573 required this.link,
1574 super.child,
1575 });
1576
1577 /// The link object that connects this [CompositedTransformTarget] with one or
1578 /// more [CompositedTransformFollower]s.
1579 ///
1580 /// The link must not be associated with another [CompositedTransformTarget]
1581 /// that is also being painted.
1582 final LayerLink link;
1583
1584 @override
1585 RenderLeaderLayer createRenderObject(BuildContext context) {
1586 return RenderLeaderLayer(
1587 link: link,
1588 );
1589 }
1590
1591 @override
1592 void updateRenderObject(BuildContext context, RenderLeaderLayer renderObject) {
1593 renderObject.link = link;
1594 }
1595}
1596
1597/// A widget that follows a [CompositedTransformTarget].
1598///
1599/// When this widget is composited during the compositing phase (which comes
1600/// after the paint phase, as described in [WidgetsBinding.drawFrame]), it
1601/// applies a transformation that brings [targetAnchor] of the linked
1602/// [CompositedTransformTarget] and [followerAnchor] of this widget together.
1603/// The two anchor points will have the same global coordinates, unless [offset]
1604/// is not [Offset.zero], in which case [followerAnchor] will be offset by
1605/// [offset] in the linked [CompositedTransformTarget]'s coordinate space.
1606///
1607/// The [LayerLink] object used as the [link] must be the same object as that
1608/// provided to the matching [CompositedTransformTarget].
1609///
1610/// The [CompositedTransformTarget] must come earlier in the paint order than
1611/// this [CompositedTransformFollower].
1612///
1613/// Hit testing on descendants of this widget will only work if the target
1614/// position is within the box that this widget's parent considers to be
1615/// hittable. If the parent covers the screen, this is trivially achievable, so
1616/// this widget is usually used as the root of an [OverlayEntry] in an app-wide
1617/// [Overlay] (e.g. as created by the [MaterialApp] widget's [Navigator]).
1618///
1619/// See also:
1620///
1621/// * [CompositedTransformTarget], the widget that this widget can target.
1622/// * [FollowerLayer], the layer that implements this widget's logic.
1623/// * [Transform], which applies an arbitrary transform to a child.
1624class CompositedTransformFollower extends SingleChildRenderObjectWidget {
1625 /// Creates a composited transform target widget.
1626 ///
1627 /// If the [link] property was also provided to a [CompositedTransformTarget],
1628 /// that widget must come earlier in the paint order.
1629 ///
1630 /// The [showWhenUnlinked] and [offset] properties must also not be null.
1631 const CompositedTransformFollower({
1632 super.key,
1633 required this.link,
1634 this.showWhenUnlinked = true,
1635 this.offset = Offset.zero,
1636 this.targetAnchor = Alignment.topLeft,
1637 this.followerAnchor = Alignment.topLeft,
1638 super.child,
1639 });
1640
1641 /// The link object that connects this [CompositedTransformFollower] with a
1642 /// [CompositedTransformTarget].
1643 final LayerLink link;
1644
1645 /// Whether to show the widget's contents when there is no corresponding
1646 /// [CompositedTransformTarget] with the same [link].
1647 ///
1648 /// When the widget is linked, the child is positioned such that it has the
1649 /// same global position as the linked [CompositedTransformTarget].
1650 ///
1651 /// When the widget is not linked, then: if [showWhenUnlinked] is true, the
1652 /// child is visible and not repositioned; if it is false, then child is
1653 /// hidden.
1654 final bool showWhenUnlinked;
1655
1656 /// The anchor point on the linked [CompositedTransformTarget] that
1657 /// [followerAnchor] will line up with.
1658 ///
1659 /// {@template flutter.widgets.CompositedTransformFollower.targetAnchor}
1660 /// For example, when [targetAnchor] and [followerAnchor] are both
1661 /// [Alignment.topLeft], this widget will be top left aligned with the linked
1662 /// [CompositedTransformTarget]. When [targetAnchor] is
1663 /// [Alignment.bottomLeft] and [followerAnchor] is [Alignment.topLeft], this
1664 /// widget will be left aligned with the linked [CompositedTransformTarget],
1665 /// and its top edge will line up with the [CompositedTransformTarget]'s
1666 /// bottom edge.
1667 /// {@endtemplate}
1668 ///
1669 /// Defaults to [Alignment.topLeft].
1670 final Alignment targetAnchor;
1671
1672 /// The anchor point on this widget that will line up with [targetAnchor] on
1673 /// the linked [CompositedTransformTarget].
1674 ///
1675 /// {@macro flutter.widgets.CompositedTransformFollower.targetAnchor}
1676 ///
1677 /// Defaults to [Alignment.topLeft].
1678 final Alignment followerAnchor;
1679
1680 /// The additional offset to apply to the [targetAnchor] of the linked
1681 /// [CompositedTransformTarget] to obtain this widget's [followerAnchor]
1682 /// position.
1683 final Offset offset;
1684
1685 @override
1686 RenderFollowerLayer createRenderObject(BuildContext context) {
1687 return RenderFollowerLayer(
1688 link: link,
1689 showWhenUnlinked: showWhenUnlinked,
1690 offset: offset,
1691 leaderAnchor: targetAnchor,
1692 followerAnchor: followerAnchor,
1693 );
1694 }
1695
1696 @override
1697 void updateRenderObject(BuildContext context, RenderFollowerLayer renderObject) {
1698 renderObject
1699 ..link = link
1700 ..showWhenUnlinked = showWhenUnlinked
1701 ..offset = offset
1702 ..leaderAnchor = targetAnchor
1703 ..followerAnchor = followerAnchor;
1704 }
1705}
1706
1707/// Scales and positions its child within itself according to [fit].
1708///
1709/// {@youtube 560 315 https://www.youtube.com/watch?v=T4Uehk3_wlY}
1710///
1711/// {@tool dartpad}
1712/// In this example, the [Placeholder] is stretched to fill the entire
1713/// [Container]. Try changing the fit types to see the effect on the layout of
1714/// the [Placeholder].
1715///
1716/// ** See code in examples/api/lib/widgets/basic/fitted_box.0.dart **
1717/// {@end-tool}
1718///
1719/// See also:
1720///
1721/// * [Transform], which applies an arbitrary transform to its child widget at
1722/// paint time.
1723/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
1724class FittedBox extends SingleChildRenderObjectWidget {
1725 /// Creates a widget that scales and positions its child within itself according to [fit].
1726 const FittedBox({
1727 super.key,
1728 this.fit = BoxFit.contain,
1729 this.alignment = Alignment.center,
1730 this.clipBehavior = Clip.none,
1731 super.child,
1732 });
1733
1734 /// How to inscribe the child into the space allocated during layout.
1735 final BoxFit fit;
1736
1737 /// How to align the child within its parent's bounds.
1738 ///
1739 /// An alignment of (-1.0, -1.0) aligns the child to the top-left corner of its
1740 /// parent's bounds. An alignment of (1.0, 0.0) aligns the child to the middle
1741 /// of the right edge of its parent's bounds.
1742 ///
1743 /// Defaults to [Alignment.center].
1744 ///
1745 /// See also:
1746 ///
1747 /// * [Alignment], a class with convenient constants typically used to
1748 /// specify an [AlignmentGeometry].
1749 /// * [AlignmentDirectional], like [Alignment] for specifying alignments
1750 /// relative to text direction.
1751 final AlignmentGeometry alignment;
1752
1753 /// {@macro flutter.material.Material.clipBehavior}
1754 ///
1755 /// Defaults to [Clip.none].
1756 final Clip clipBehavior;
1757
1758 @override
1759 RenderFittedBox createRenderObject(BuildContext context) {
1760 return RenderFittedBox(
1761 fit: fit,
1762 alignment: alignment,
1763 textDirection: Directionality.maybeOf(context),
1764 clipBehavior: clipBehavior,
1765 );
1766 }
1767
1768 @override
1769 void updateRenderObject(BuildContext context, RenderFittedBox renderObject) {
1770 renderObject
1771 ..fit = fit
1772 ..alignment = alignment
1773 ..textDirection = Directionality.maybeOf(context)
1774 ..clipBehavior = clipBehavior;
1775 }
1776
1777 @override
1778 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1779 super.debugFillProperties(properties);
1780 properties.add(EnumProperty<BoxFit>('fit', fit));
1781 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
1782 }
1783}
1784
1785/// Applies a translation transformation before painting its child.
1786///
1787/// The translation is expressed as a [Offset] scaled to the child's size. For
1788/// example, an [Offset] with a `dx` of 0.25 will result in a horizontal
1789/// translation of one quarter the width of the child.
1790///
1791/// Hit tests will only be detected inside the bounds of the
1792/// [FractionalTranslation], even if the contents are offset such that
1793/// they overflow.
1794///
1795/// See also:
1796///
1797/// * [Transform], which applies an arbitrary transform to its child widget at
1798/// paint time.
1799/// * [Transform.translate], which applies an absolute offset translation
1800/// transformation instead of an offset scaled to the child.
1801/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
1802class FractionalTranslation extends SingleChildRenderObjectWidget {
1803 /// Creates a widget that translates its child's painting.
1804 const FractionalTranslation({
1805 super.key,
1806 required this.translation,
1807 this.transformHitTests = true,
1808 super.child,
1809 });
1810
1811 /// The translation to apply to the child, scaled to the child's size.
1812 ///
1813 /// For example, an [Offset] with a `dx` of 0.25 will result in a horizontal
1814 /// translation of one quarter the width of the child.
1815 final Offset translation;
1816
1817 /// Whether to apply the translation when performing hit tests.
1818 final bool transformHitTests;
1819
1820 @override
1821 RenderFractionalTranslation createRenderObject(BuildContext context) {
1822 return RenderFractionalTranslation(
1823 translation: translation,
1824 transformHitTests: transformHitTests,
1825 );
1826 }
1827
1828 @override
1829 void updateRenderObject(BuildContext context, RenderFractionalTranslation renderObject) {
1830 renderObject
1831 ..translation = translation
1832 ..transformHitTests = transformHitTests;
1833 }
1834}
1835
1836/// A widget that rotates its child by a integral number of quarter turns.
1837///
1838/// Unlike [Transform], which applies a transform just prior to painting,
1839/// this object applies its rotation prior to layout, which means the entire
1840/// rotated box consumes only as much space as required by the rotated child.
1841///
1842/// {@youtube 560 315 https://www.youtube.com/watch?v=BFE6_UglLfQ}
1843///
1844/// {@tool snippet}
1845///
1846/// This snippet rotates the child (some [Text]) so that it renders from bottom
1847/// to top, like an axis label on a graph:
1848///
1849/// ```dart
1850/// const RotatedBox(
1851/// quarterTurns: 3,
1852/// child: Text('Hello World!'),
1853/// )
1854/// ```
1855/// {@end-tool}
1856///
1857/// See also:
1858///
1859/// * [Transform], which is a paint effect that allows you to apply an
1860/// arbitrary transform to a child.
1861/// * [Transform.rotate], which applies a rotation paint effect.
1862/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
1863class RotatedBox extends SingleChildRenderObjectWidget {
1864 /// A widget that rotates its child.
1865 const RotatedBox({
1866 super.key,
1867 required this.quarterTurns,
1868 super.child,
1869 });
1870
1871 /// The number of clockwise quarter turns the child should be rotated.
1872 final int quarterTurns;
1873
1874 @override
1875 RenderRotatedBox createRenderObject(BuildContext context) => RenderRotatedBox(quarterTurns: quarterTurns);
1876
1877 @override
1878 void updateRenderObject(BuildContext context, RenderRotatedBox renderObject) {
1879 renderObject.quarterTurns = quarterTurns;
1880 }
1881}
1882
1883/// A widget that insets its child by the given padding.
1884///
1885/// {@youtube 560 315 https://www.youtube.com/watch?v=oD5RtLhhubg}
1886///
1887/// When passing layout constraints to its child, padding shrinks the
1888/// constraints by the given padding, causing the child to layout at a smaller
1889/// size. Padding then sizes itself to its child's size, inflated by the
1890/// padding, effectively creating empty space around the child.
1891///
1892/// {@tool snippet}
1893///
1894/// This snippet creates "Hello World!" [Text] inside a [Card] that is indented
1895/// by sixteen pixels in each direction.
1896///
1897/// ![](https://flutter.github.io/assets-for-api-docs/assets/widgets/padding.png)
1898///
1899/// ```dart
1900/// const Card(
1901/// child: Padding(
1902/// padding: EdgeInsets.all(16.0),
1903/// child: Text('Hello World!'),
1904/// ),
1905/// )
1906/// ```
1907/// {@end-tool}
1908///
1909/// ## Design discussion
1910///
1911/// ### Why use a [Padding] widget rather than a [Container] with a [Container.padding] property?
1912///
1913/// There isn't really any difference between the two. If you supply a
1914/// [Container.padding] argument, [Container] builds a [Padding] widget
1915/// for you.
1916///
1917/// [Container] doesn't implement its properties directly. Instead, [Container]
1918/// combines a number of simpler widgets together into a convenient package. For
1919/// example, the [Container.padding] property causes the container to build a
1920/// [Padding] widget and the [Container.decoration] property causes the
1921/// container to build a [DecoratedBox] widget. If you find [Container]
1922/// convenient, feel free to use it. If not, feel free to build these simpler
1923/// widgets in whatever combination meets your needs.
1924///
1925/// In fact, the majority of widgets in Flutter are combinations of other
1926/// simpler widgets. Composition, rather than inheritance, is the primary
1927/// mechanism for building up widgets.
1928///
1929/// See also:
1930///
1931/// * [EdgeInsets], the class that is used to describe the padding dimensions.
1932/// * [AnimatedPadding], which animates changes in [padding] over a given
1933/// duration.
1934/// * [SliverPadding], the sliver equivalent of this widget.
1935/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
1936class Padding extends SingleChildRenderObjectWidget {
1937 /// Creates a widget that insets its child.
1938 const Padding({
1939 super.key,
1940 required this.padding,
1941 super.child,
1942 });
1943
1944 /// The amount of space by which to inset the child.
1945 final EdgeInsetsGeometry padding;
1946
1947 @override
1948 RenderPadding createRenderObject(BuildContext context) {
1949 return RenderPadding(
1950 padding: padding,
1951 textDirection: Directionality.maybeOf(context),
1952 );
1953 }
1954
1955 @override
1956 void updateRenderObject(BuildContext context, RenderPadding renderObject) {
1957 renderObject
1958 ..padding = padding
1959 ..textDirection = Directionality.maybeOf(context);
1960 }
1961
1962 @override
1963 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1964 super.debugFillProperties(properties);
1965 properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding));
1966 }
1967}
1968
1969/// A widget that aligns its child within itself and optionally sizes itself
1970/// based on the child's size.
1971///
1972/// For example, to align a box at the bottom right, you would pass this box a
1973/// tight constraint that is bigger than the child's natural size,
1974/// with an alignment of [Alignment.bottomRight].
1975///
1976/// {@youtube 560 315 https://www.youtube.com/watch?v=g2E7yl3MwMk}
1977///
1978/// This widget will be as big as possible if its dimensions are constrained and
1979/// [widthFactor] and [heightFactor] are null. If a dimension is unconstrained
1980/// and the corresponding size factor is null then the widget will match its
1981/// child's size in that dimension. If a size factor is non-null then the
1982/// corresponding dimension of this widget will be the product of the child's
1983/// dimension and the size factor. For example if widthFactor is 2.0 then
1984/// the width of this widget will always be twice its child's width.
1985///
1986/// {@tool snippet}
1987/// The [Align] widget in this example uses one of the defined constants from
1988/// [Alignment], [Alignment.topRight]. This places the [FlutterLogo] in the top
1989/// right corner of the parent blue [Container].
1990///
1991/// ![A blue square container with the Flutter logo in the top right corner.](https://flutter.github.io/assets-for-api-docs/assets/widgets/align_constant.png)
1992///
1993/// ```dart
1994/// Center(
1995/// child: Container(
1996/// height: 120.0,
1997/// width: 120.0,
1998/// color: Colors.blue[50],
1999/// child: const Align(
2000/// alignment: Alignment.topRight,
2001/// child: FlutterLogo(
2002/// size: 60,
2003/// ),
2004/// ),
2005/// ),
2006/// )
2007/// ```
2008/// {@end-tool}
2009///
2010/// ## How it works
2011///
2012/// The [alignment] property describes a point in the `child`'s coordinate system
2013/// and a different point in the coordinate system of this widget. The [Align]
2014/// widget positions the `child` such that both points are lined up on top of
2015/// each other.
2016///
2017/// {@tool snippet}
2018/// The [Alignment] used in the following example defines two points:
2019///
2020/// * (0.2 * width of [FlutterLogo]/2 + width of [FlutterLogo]/2, 0.6 * height
2021/// of [FlutterLogo]/2 + height of [FlutterLogo]/2) = (36.0, 48.0) in the
2022/// coordinate system of the [FlutterLogo].
2023/// * (0.2 * width of [Align]/2 + width of [Align]/2, 0.6 * height
2024/// of [Align]/2 + height of [Align]/2) = (72.0, 96.0) in the
2025/// coordinate system of the [Align] widget (blue area).
2026///
2027/// The [Align] widget positions the [FlutterLogo] such that the two points are on
2028/// top of each other. In this example, the top left of the [FlutterLogo] will
2029/// be placed at (72.0, 96.0) - (36.0, 48.0) = (36.0, 48.0) from the top left of
2030/// the [Align] widget.
2031///
2032/// ![A blue square container with the Flutter logo positioned according to the
2033/// Alignment specified above. A point is marked at the center of the container
2034/// for the origin of the Alignment coordinate system.](https://flutter.github.io/assets-for-api-docs/assets/widgets/align_alignment.png)
2035///
2036/// ```dart
2037/// Center(
2038/// child: Container(
2039/// height: 120.0,
2040/// width: 120.0,
2041/// color: Colors.blue[50],
2042/// child: const Align(
2043/// alignment: Alignment(0.2, 0.6),
2044/// child: FlutterLogo(
2045/// size: 60,
2046/// ),
2047/// ),
2048/// ),
2049/// )
2050/// ```
2051/// {@end-tool}
2052///
2053/// {@tool snippet}
2054/// The [FractionalOffset] used in the following example defines two points:
2055///
2056/// * (0.2 * width of [FlutterLogo], 0.6 * height of [FlutterLogo]) = (12.0, 36.0)
2057/// in the coordinate system of the [FlutterLogo].
2058/// * (0.2 * width of [Align], 0.6 * height of [Align]) = (24.0, 72.0) in the
2059/// coordinate system of the [Align] widget (blue area).
2060///
2061/// The [Align] widget positions the [FlutterLogo] such that the two points are on
2062/// top of each other. In this example, the top left of the [FlutterLogo] will
2063/// be placed at (24.0, 72.0) - (12.0, 36.0) = (12.0, 36.0) from the top left of
2064/// the [Align] widget.
2065///
2066/// The [FractionalOffset] class uses a coordinate system with an origin in the top-left
2067/// corner of the [Container] in difference to the center-oriented system used in
2068/// the example above with [Alignment].
2069///
2070/// ![A blue square container with the Flutter logo positioned according to the
2071/// FractionalOffset specified above. A point is marked at the top left corner
2072/// of the container for the origin of the FractionalOffset coordinate system.](https://flutter.github.io/assets-for-api-docs/assets/widgets/align_fractional_offset.png)
2073///
2074/// ```dart
2075/// Center(
2076/// child: Container(
2077/// height: 120.0,
2078/// width: 120.0,
2079/// color: Colors.blue[50],
2080/// child: const Align(
2081/// alignment: FractionalOffset(0.2, 0.6),
2082/// child: FlutterLogo(
2083/// size: 60,
2084/// ),
2085/// ),
2086/// ),
2087/// )
2088/// ```
2089/// {@end-tool}
2090///
2091/// See also:
2092///
2093/// * [AnimatedAlign], which animates changes in [alignment] smoothly over a
2094/// given duration.
2095/// * [CustomSingleChildLayout], which uses a delegate to control the layout of
2096/// a single child.
2097/// * [Center], which is the same as [Align] but with the [alignment] always
2098/// set to [Alignment.center].
2099/// * [FractionallySizedBox], which sizes its child based on a fraction of its
2100/// own size and positions the child according to an [Alignment] value.
2101/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
2102class Align extends SingleChildRenderObjectWidget {
2103 /// Creates an alignment widget.
2104 ///
2105 /// The alignment defaults to [Alignment.center].
2106 const Align({
2107 super.key,
2108 this.alignment = Alignment.center,
2109 this.widthFactor,
2110 this.heightFactor,
2111 super.child,
2112 }) : assert(widthFactor == null || widthFactor >= 0.0),
2113 assert(heightFactor == null || heightFactor >= 0.0);
2114
2115 /// How to align the child.
2116 ///
2117 /// The x and y values of the [Alignment] control the horizontal and vertical
2118 /// alignment, respectively. An x value of -1.0 means that the left edge of
2119 /// the child is aligned with the left edge of the parent whereas an x value
2120 /// of 1.0 means that the right edge of the child is aligned with the right
2121 /// edge of the parent. Other values interpolate (and extrapolate) linearly.
2122 /// For example, a value of 0.0 means that the center of the child is aligned
2123 /// with the center of the parent.
2124 ///
2125 /// See also:
2126 ///
2127 /// * [Alignment], which has more details and some convenience constants for
2128 /// common positions.
2129 /// * [AlignmentDirectional], which has a horizontal coordinate orientation
2130 /// that depends on the [TextDirection].
2131 final AlignmentGeometry alignment;
2132
2133 /// If non-null, sets its width to the child's width multiplied by this factor.
2134 ///
2135 /// Can be both greater and less than 1.0 but must be non-negative.
2136 final double? widthFactor;
2137
2138 /// If non-null, sets its height to the child's height multiplied by this factor.
2139 ///
2140 /// Can be both greater and less than 1.0 but must be non-negative.
2141 final double? heightFactor;
2142
2143 @override
2144 RenderPositionedBox createRenderObject(BuildContext context) {
2145 return RenderPositionedBox(
2146 alignment: alignment,
2147 widthFactor: widthFactor,
2148 heightFactor: heightFactor,
2149 textDirection: Directionality.maybeOf(context),
2150 );
2151 }
2152
2153 @override
2154 void updateRenderObject(BuildContext context, RenderPositionedBox renderObject) {
2155 renderObject
2156 ..alignment = alignment
2157 ..widthFactor = widthFactor
2158 ..heightFactor = heightFactor
2159 ..textDirection = Directionality.maybeOf(context);
2160 }
2161
2162 @override
2163 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
2164 super.debugFillProperties(properties);
2165 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
2166 properties.add(DoubleProperty('widthFactor', widthFactor, defaultValue: null));
2167 properties.add(DoubleProperty('heightFactor', heightFactor, defaultValue: null));
2168 }
2169}
2170
2171/// A widget that centers its child within itself.
2172///
2173/// This widget will be as big as possible if its dimensions are constrained and
2174/// [widthFactor] and [heightFactor] are null. If a dimension is unconstrained
2175/// and the corresponding size factor is null then the widget will match its
2176/// child's size in that dimension. If a size factor is non-null then the
2177/// corresponding dimension of this widget will be the product of the child's
2178/// dimension and the size factor. For example if widthFactor is 2.0 then
2179/// the width of this widget will always be twice its child's width.
2180///
2181/// See also:
2182///
2183/// * [Align], which lets you arbitrarily position a child within itself,
2184/// rather than just centering it.
2185/// * [Row], a widget that displays its children in a horizontal array.
2186/// * [Column], a widget that displays its children in a vertical array.
2187/// * [Container], a convenience widget that combines common painting,
2188/// positioning, and sizing widgets.
2189/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
2190class Center extends Align {
2191 /// Creates a widget that centers its child.
2192 const Center({ super.key, super.widthFactor, super.heightFactor, super.child });
2193}
2194
2195/// A widget that defers the layout of its single child to a delegate.
2196///
2197/// The delegate can determine the layout constraints for the child and can
2198/// decide where to position the child. The delegate can also determine the size
2199/// of the parent, but the size of the parent cannot depend on the size of the
2200/// child.
2201///
2202/// See also:
2203///
2204/// * [SingleChildLayoutDelegate], which controls the layout of the child.
2205/// * [Align], which sizes itself based on its child's size and positions
2206/// the child according to an [Alignment] value.
2207/// * [FractionallySizedBox], which sizes its child based on a fraction of its own
2208/// size and positions the child according to an [Alignment] value.
2209/// * [CustomMultiChildLayout], which uses a delegate to position multiple
2210/// children.
2211/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
2212class CustomSingleChildLayout extends SingleChildRenderObjectWidget {
2213 /// Creates a custom single child layout.
2214 const CustomSingleChildLayout({
2215 super.key,
2216 required this.delegate,
2217 super.child,
2218 });
2219
2220 /// The delegate that controls the layout of the child.
2221 final SingleChildLayoutDelegate delegate;
2222
2223 @override
2224 RenderCustomSingleChildLayoutBox createRenderObject(BuildContext context) {
2225 return RenderCustomSingleChildLayoutBox(delegate: delegate);
2226 }
2227
2228 @override
2229 void updateRenderObject(BuildContext context, RenderCustomSingleChildLayoutBox renderObject) {
2230 renderObject.delegate = delegate;
2231 }
2232}
2233
2234/// Metadata for identifying children in a [CustomMultiChildLayout].
2235///
2236/// The [MultiChildLayoutDelegate.hasChild],
2237/// [MultiChildLayoutDelegate.layoutChild], and
2238/// [MultiChildLayoutDelegate.positionChild] methods use these identifiers.
2239class LayoutId extends ParentDataWidget<MultiChildLayoutParentData> {
2240 /// Marks a child with a layout identifier.
2241 LayoutId({
2242 Key? key,
2243 required this.id,
2244 required super.child,
2245 }) : super(key: key ?? ValueKey<Object>(id));
2246
2247 /// An object representing the identity of this child.
2248 ///
2249 /// The [id] needs to be unique among the children that the
2250 /// [CustomMultiChildLayout] manages.
2251 final Object id;
2252
2253 @override
2254 void applyParentData(RenderObject renderObject) {
2255 assert(renderObject.parentData is MultiChildLayoutParentData);
2256 final MultiChildLayoutParentData parentData = renderObject.parentData! as MultiChildLayoutParentData;
2257 if (parentData.id != id) {
2258 parentData.id = id;
2259 final RenderObject? targetParent = renderObject.parent;
2260 if (targetParent is RenderObject) {
2261 targetParent.markNeedsLayout();
2262 }
2263 }
2264 }
2265
2266 @override
2267 Type get debugTypicalAncestorWidgetClass => CustomMultiChildLayout;
2268
2269 @override
2270 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
2271 super.debugFillProperties(properties);
2272 properties.add(DiagnosticsProperty<Object>('id', id));
2273 }
2274}
2275
2276/// A widget that uses a delegate to size and position multiple children.
2277///
2278/// The delegate can determine the layout constraints for each child and can
2279/// decide where to position each child. The delegate can also determine the
2280/// size of the parent, but the size of the parent cannot depend on the sizes of
2281/// the children.
2282///
2283/// [CustomMultiChildLayout] is appropriate when there are complex relationships
2284/// between the size and positioning of multiple widgets. To control the
2285/// layout of a single child, [CustomSingleChildLayout] is more appropriate. For
2286/// simple cases, such as aligning a widget to one or another edge, the [Stack]
2287/// widget is more appropriate.
2288///
2289/// Each child must be wrapped in a [LayoutId] widget to identify the widget for
2290/// the delegate.
2291///
2292/// {@tool dartpad}
2293/// This example shows a [CustomMultiChildLayout] widget being used to lay out
2294/// colored blocks from start to finish in a cascade that has some overlap.
2295///
2296/// It responds to changes in [Directionality] by re-laying out its children.
2297///
2298/// ** See code in examples/api/lib/widgets/basic/custom_multi_child_layout.0.dart **
2299/// {@end-tool}
2300///
2301/// See also:
2302///
2303/// * [MultiChildLayoutDelegate], for details about how to control the layout of
2304/// the children.
2305/// * [CustomSingleChildLayout], which uses a delegate to control the layout of
2306/// a single child.
2307/// * [Stack], which arranges children relative to the edges of the container.
2308/// * [Flow], which provides paint-time control of its children using transform
2309/// matrices.
2310/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
2311class CustomMultiChildLayout extends MultiChildRenderObjectWidget {
2312 /// Creates a custom multi-child layout.
2313 const CustomMultiChildLayout({
2314 super.key,
2315 required this.delegate,
2316 super.children,
2317 });
2318
2319 /// The delegate that controls the layout of the children.
2320 final MultiChildLayoutDelegate delegate;
2321
2322 @override
2323 RenderCustomMultiChildLayoutBox createRenderObject(BuildContext context) {
2324 return RenderCustomMultiChildLayoutBox(delegate: delegate);
2325 }
2326
2327 @override
2328 void updateRenderObject(BuildContext context, RenderCustomMultiChildLayoutBox renderObject) {
2329 renderObject.delegate = delegate;
2330 }
2331}
2332
2333/// A box with a specified size.
2334///
2335/// If given a child, this widget forces it to have a specific width and/or height.
2336/// These values will be ignored if this widget's parent does not permit them.
2337/// For example, this happens if the parent is the screen (forces the child to
2338/// be the same size as the parent), or another [SizedBox] (forces its child to
2339/// have a specific width and/or height). This can be remedied by wrapping the
2340/// child [SizedBox] in a widget that does permit it to be any size up to the
2341/// size of the parent, such as [Center] or [Align].
2342///
2343/// If either the width or height is null, this widget will try to size itself to
2344/// match the child's size in that dimension. If the child's size depends on the
2345/// size of its parent, the height and width must be provided.
2346///
2347/// If not given a child, [SizedBox] will try to size itself as close to the
2348/// specified height and width as possible given the parent's constraints. If
2349/// [height] or [width] is null or unspecified, it will be treated as zero.
2350///
2351/// The [SizedBox.expand] constructor can be used to make a [SizedBox] that
2352/// sizes itself to fit the parent. It is equivalent to setting [width] and
2353/// [height] to [double.infinity].
2354///
2355/// {@youtube 560 315 https://www.youtube.com/watch?v=EHPu_DzRfqA}
2356///
2357/// {@tool snippet}
2358///
2359/// This snippet makes the child widget (a [Card] with some [Text]) have the
2360/// exact size 200x300, parental constraints permitting:
2361///
2362/// ```dart
2363/// const SizedBox(
2364/// width: 200.0,
2365/// height: 300.0,
2366/// child: Card(child: Text('Hello World!')),
2367/// )
2368/// ```
2369/// {@end-tool}
2370///
2371/// See also:
2372///
2373/// * [ConstrainedBox], a more generic version of this class that takes
2374/// arbitrary [BoxConstraints] instead of an explicit width and height.
2375/// * [UnconstrainedBox], a container that tries to let its child draw without
2376/// constraints.
2377/// * [FractionallySizedBox], a widget that sizes its child to a fraction of
2378/// the total available space.
2379/// * [AspectRatio], a widget that attempts to fit within the parent's
2380/// constraints while also sizing its child to match a given aspect ratio.
2381/// * [FittedBox], which sizes and positions its child widget to fit the parent
2382/// according to a given [BoxFit] discipline.
2383/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
2384/// * [Understanding constraints](https://flutter.dev/docs/development/ui/layout/constraints),
2385/// an in-depth article about layout in Flutter.
2386class SizedBox extends SingleChildRenderObjectWidget {
2387 /// Creates a fixed size box. The [width] and [height] parameters can be null
2388 /// to indicate that the size of the box should not be constrained in
2389 /// the corresponding dimension.
2390 const SizedBox({ super.key, this.width, this.height, super.child });
2391
2392 /// Creates a box that will become as large as its parent allows.
2393 const SizedBox.expand({ super.key, super.child })
2394 : width = double.infinity,
2395 height = double.infinity;
2396
2397 /// Creates a box that will become as small as its parent allows.
2398 const SizedBox.shrink({ super.key, super.child })
2399 : width = 0.0,
2400 height = 0.0;
2401
2402 /// Creates a box with the specified size.
2403 SizedBox.fromSize({ super.key, super.child, Size? size })
2404 : width = size?.width,
2405 height = size?.height;
2406
2407 /// Creates a box whose [width] and [height] are equal.
2408 const SizedBox.square({super.key, super.child, double? dimension})
2409 : width = dimension,
2410 height = dimension;
2411
2412 /// If non-null, requires the child to have exactly this width.
2413 final double? width;
2414
2415 /// If non-null, requires the child to have exactly this height.
2416 final double? height;
2417
2418 @override
2419 RenderConstrainedBox createRenderObject(BuildContext context) {
2420 return RenderConstrainedBox(
2421 additionalConstraints: _additionalConstraints,
2422 );
2423 }
2424
2425 BoxConstraints get _additionalConstraints {
2426 return BoxConstraints.tightFor(width: width, height: height);
2427 }
2428
2429 @override
2430 void updateRenderObject(BuildContext context, RenderConstrainedBox renderObject) {
2431 renderObject.additionalConstraints = _additionalConstraints;
2432 }
2433
2434 @override
2435 String toStringShort() {
2436 final String type;
2437 if (width == double.infinity && height == double.infinity) {
2438 type = '${objectRuntimeType(this, 'SizedBox')}.expand';
2439 } else if (width == 0.0 && height == 0.0) {
2440 type = '${objectRuntimeType(this, 'SizedBox')}.shrink';
2441 } else {
2442 type = objectRuntimeType(this, 'SizedBox');
2443 }
2444 return key == null ? type : '$type-$key';
2445 }
2446
2447 @override
2448 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
2449 super.debugFillProperties(properties);
2450 final DiagnosticLevel level;
2451 if ((width == double.infinity && height == double.infinity) ||
2452 (width == 0.0 && height == 0.0)) {
2453 level = DiagnosticLevel.hidden;
2454 } else {
2455 level = DiagnosticLevel.info;
2456 }
2457 properties.add(DoubleProperty('width', width, defaultValue: null, level: level));
2458 properties.add(DoubleProperty('height', height, defaultValue: null, level: level));
2459 }
2460}
2461
2462/// A widget that imposes additional constraints on its child.
2463///
2464/// For example, if you wanted [child] to have a minimum height of 50.0 logical
2465/// pixels, you could use `const BoxConstraints(minHeight: 50.0)` as the
2466/// [constraints].
2467///
2468/// {@youtube 560 315 https://www.youtube.com/watch?v=o2KveVr7adg}
2469///
2470/// {@tool snippet}
2471///
2472/// This snippet makes the child widget (a [Card] with some [Text]) fill the
2473/// parent, by applying [BoxConstraints.expand] constraints:
2474///
2475/// ```dart
2476/// ConstrainedBox(
2477/// constraints: const BoxConstraints.expand(),
2478/// child: const Card(child: Text('Hello World!')),
2479/// )
2480/// ```
2481/// {@end-tool}
2482///
2483/// The same behavior can be obtained using the [SizedBox.expand] widget.
2484///
2485/// See also:
2486///
2487/// * [BoxConstraints], the class that describes constraints.
2488/// * [UnconstrainedBox], a container that tries to let its child draw without
2489/// constraints.
2490/// * [SizedBox], which lets you specify tight constraints by explicitly
2491/// specifying the height or width.
2492/// * [FractionallySizedBox], which sizes its child based on a fraction of its
2493/// own size and positions the child according to an [Alignment] value.
2494/// * [AspectRatio], a widget that attempts to fit within the parent's
2495/// constraints while also sizing its child to match a given aspect ratio.
2496/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
2497class ConstrainedBox extends SingleChildRenderObjectWidget {
2498 /// Creates a widget that imposes additional constraints on its child.
2499 ConstrainedBox({
2500 super.key,
2501 required this.constraints,
2502 super.child,
2503 }) : assert(constraints.debugAssertIsValid());
2504
2505 /// The additional constraints to impose on the child.
2506 final BoxConstraints constraints;
2507
2508 @override
2509 RenderConstrainedBox createRenderObject(BuildContext context) {
2510 return RenderConstrainedBox(additionalConstraints: constraints);
2511 }
2512
2513 @override
2514 void updateRenderObject(BuildContext context, RenderConstrainedBox renderObject) {
2515 renderObject.additionalConstraints = constraints;
2516 }
2517
2518 @override
2519 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
2520 super.debugFillProperties(properties);
2521 properties.add(DiagnosticsProperty<BoxConstraints>('constraints', constraints, showName: false));
2522 }
2523}
2524
2525/// A container widget that applies an arbitrary transform to its constraints,
2526/// and sizes its child using the resulting [BoxConstraints], optionally
2527/// clipping, or treating the overflow as an error.
2528///
2529/// This container sizes its child using a [BoxConstraints] created by applying
2530/// [constraintsTransform] to its own constraints. This container will then
2531/// attempt to adopt the same size, within the limits of its own constraints. If
2532/// it ends up with a different size, it will align the child based on
2533/// [alignment]. If the container cannot expand enough to accommodate the entire
2534/// child, the child will be clipped if [clipBehavior] is not [Clip.none].
2535///
2536/// In debug mode, if [clipBehavior] is [Clip.none] and the child overflows the
2537/// container, a warning will be printed on the console, and black and yellow
2538/// striped areas will appear where the overflow occurs.
2539///
2540/// When [child] is null, this widget becomes as small as possible and never
2541/// overflows.
2542///
2543/// This widget can be used to ensure some of [child]'s natural dimensions are
2544/// honored, and get an early warning otherwise during development. For
2545/// instance, if [child] requires a minimum height to fully display its content,
2546/// [constraintsTransform] can be set to [maxHeightUnconstrained], so that if
2547/// the parent [RenderObject] fails to provide enough vertical space, a warning
2548/// will be displayed in debug mode, while still allowing [child] to grow
2549/// vertically:
2550///
2551/// {@tool snippet}
2552/// In the following snippet, the [Card] is guaranteed to be at least as tall as
2553/// its "natural" height. Unlike [UnconstrainedBox], it will become taller if
2554/// its "natural" height is smaller than 40 px. If the [Container] isn't high
2555/// enough to show the full content of the [Card], in debug mode a warning will
2556/// be given.
2557///
2558/// ```dart
2559/// Container(
2560/// constraints: const BoxConstraints(minHeight: 40, maxHeight: 100),
2561/// alignment: Alignment.center,
2562/// child: const ConstraintsTransformBox(
2563/// constraintsTransform: ConstraintsTransformBox.maxHeightUnconstrained,
2564/// child: Card(child: Text('Hello World!')),
2565/// )
2566/// )
2567/// ```
2568/// {@end-tool}
2569///
2570/// See also:
2571///
2572/// * [ConstrainedBox], which renders a box which imposes constraints
2573/// on its child.
2574/// * [OverflowBox], a widget that imposes additional constraints on its child,
2575/// and allows the child to overflow itself.
2576/// * [UnconstrainedBox] which allows its children to render themselves
2577/// unconstrained and expands to fit them.
2578class ConstraintsTransformBox extends SingleChildRenderObjectWidget {
2579 /// Creates a widget that uses a function to transform the constraints it
2580 /// passes to its child. If the child overflows the parent's constraints, a
2581 /// warning will be given in debug mode.
2582 ///
2583 /// The `debugTransformType` argument adds a debug label to this widget.
2584 ///
2585 /// The `alignment`, `clipBehavior` and `constraintsTransform` arguments must
2586 /// not be null.
2587 const ConstraintsTransformBox({
2588 super.key,
2589 super.child,
2590 this.textDirection,
2591 this.alignment = Alignment.center,
2592 required this.constraintsTransform,
2593 this.clipBehavior = Clip.none,
2594 String debugTransformType = '',
2595 }) : _debugTransformLabel = debugTransformType;
2596
2597 /// A [BoxConstraintsTransform] that always returns its argument as-is (i.e.,
2598 /// it is an identity function).
2599 ///
2600 /// The [ConstraintsTransformBox] becomes a proxy widget that has no effect on
2601 /// layout if [constraintsTransform] is set to this.
2602 static BoxConstraints unmodified(BoxConstraints constraints) => constraints;
2603
2604 /// A [BoxConstraintsTransform] that always returns a [BoxConstraints] that
2605 /// imposes no constraints on either dimension (i.e. `const BoxConstraints()`).
2606 ///
2607 /// Setting [constraintsTransform] to this allows [child] to render at its
2608 /// "natural" size (equivalent to an [UnconstrainedBox] with `constrainedAxis`
2609 /// set to null).
2610 static BoxConstraints unconstrained(BoxConstraints constraints) => const BoxConstraints();
2611
2612 /// A [BoxConstraintsTransform] that removes the width constraints from the
2613 /// input.
2614 ///
2615 /// Setting [constraintsTransform] to this allows [child] to render at its
2616 /// "natural" width (equivalent to an [UnconstrainedBox] with
2617 /// `constrainedAxis` set to [Axis.horizontal]).
2618 static BoxConstraints widthUnconstrained(BoxConstraints constraints) => constraints.heightConstraints();
2619
2620 /// A [BoxConstraintsTransform] that removes the height constraints from the
2621 /// input.
2622 ///
2623 /// Setting [constraintsTransform] to this allows [child] to render at its
2624 /// "natural" height (equivalent to an [UnconstrainedBox] with
2625 /// `constrainedAxis` set to [Axis.vertical]).
2626 static BoxConstraints heightUnconstrained(BoxConstraints constraints) => constraints.widthConstraints();
2627
2628 /// A [BoxConstraintsTransform] that removes the `maxHeight` constraint from
2629 /// the input.
2630 ///
2631 /// Setting [constraintsTransform] to this allows [child] to render at its
2632 /// "natural" height or the `minHeight` of the incoming [BoxConstraints],
2633 /// whichever is larger.
2634 static BoxConstraints maxHeightUnconstrained(BoxConstraints constraints) => constraints.copyWith(maxHeight: double.infinity);
2635
2636 /// A [BoxConstraintsTransform] that removes the `maxWidth` constraint from
2637 /// the input.
2638 ///
2639 /// Setting [constraintsTransform] to this allows [child] to render at its
2640 /// "natural" width or the `minWidth` of the incoming [BoxConstraints],
2641 /// whichever is larger.
2642 static BoxConstraints maxWidthUnconstrained(BoxConstraints constraints) => constraints.copyWith(maxWidth: double.infinity);
2643
2644 /// A [BoxConstraintsTransform] that removes both the `maxWidth` and the
2645 /// `maxHeight` constraints from the input.
2646 ///
2647 /// Setting [constraintsTransform] to this allows [child] to render at least
2648 /// its "natural" size, and grow along an axis if the incoming
2649 /// [BoxConstraints] has a larger minimum constraint on that axis.
2650 static BoxConstraints maxUnconstrained(BoxConstraints constraints) => constraints.copyWith(maxWidth: double.infinity, maxHeight: double.infinity);
2651
2652 static final Map<BoxConstraintsTransform, String> _debugKnownTransforms = <BoxConstraintsTransform, String>{
2653 unmodified: 'unmodified',
2654 unconstrained: 'unconstrained',
2655 widthUnconstrained: 'width constraints removed',
2656 heightUnconstrained: 'height constraints removed',
2657 maxWidthUnconstrained: 'maxWidth constraint removed',
2658 maxHeightUnconstrained: 'maxHeight constraint removed',
2659 maxUnconstrained: 'maxWidth & maxHeight constraints removed',
2660 };
2661
2662 /// The text direction to use when interpreting the [alignment] if it is an
2663 /// [AlignmentDirectional].
2664 ///
2665 /// Defaults to null, in which case [Directionality.maybeOf] is used to determine
2666 /// the text direction.
2667 final TextDirection? textDirection;
2668
2669 /// The alignment to use when laying out the child, if it has a different size
2670 /// than this widget.
2671 ///
2672 /// If this is an [AlignmentDirectional], then [textDirection] must not be
2673 /// null.
2674 ///
2675 /// See also:
2676 ///
2677 /// * [Alignment] for non-[Directionality]-aware alignments.
2678 /// * [AlignmentDirectional] for [Directionality]-aware alignments.
2679 final AlignmentGeometry alignment;
2680
2681 /// {@template flutter.widgets.constraintsTransform}
2682 /// The function used to transform the incoming [BoxConstraints], to size
2683 /// [child].
2684 ///
2685 /// The function must return a [BoxConstraints] that is
2686 /// [BoxConstraints.isNormalized].
2687 ///
2688 /// See [ConstraintsTransformBox] for predefined common
2689 /// [BoxConstraintsTransform]s.
2690 /// {@endtemplate}
2691 final BoxConstraintsTransform constraintsTransform;
2692
2693 /// {@macro flutter.material.Material.clipBehavior}
2694 ///
2695 /// {@template flutter.widgets.ConstraintsTransformBox.clipBehavior}
2696 /// In debug mode, if [clipBehavior] is [Clip.none], and the child overflows
2697 /// its constraints, a warning will be printed on the console, and black and
2698 /// yellow striped areas will appear where the overflow occurs. For other
2699 /// values of [clipBehavior], the contents are clipped accordingly.
2700 /// {@endtemplate}
2701 ///
2702 /// Defaults to [Clip.none].
2703 final Clip clipBehavior;
2704
2705 final String _debugTransformLabel;
2706
2707 @override
2708 RenderConstraintsTransformBox createRenderObject(BuildContext context) {
2709 return RenderConstraintsTransformBox(
2710 textDirection: textDirection ?? Directionality.maybeOf(context),
2711 alignment: alignment,
2712 constraintsTransform: constraintsTransform,
2713 clipBehavior: clipBehavior,
2714 );
2715 }
2716
2717 @override
2718 void updateRenderObject(BuildContext context, covariant RenderConstraintsTransformBox renderObject) {
2719 renderObject
2720 ..textDirection = textDirection ?? Directionality.maybeOf(context)
2721 ..constraintsTransform = constraintsTransform
2722 ..alignment = alignment
2723 ..clipBehavior = clipBehavior;
2724 }
2725
2726 @override
2727 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
2728 super.debugFillProperties(properties);
2729 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
2730 properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
2731
2732 final String? debugTransformLabel = _debugTransformLabel.isNotEmpty
2733 ? _debugTransformLabel
2734 : _debugKnownTransforms[constraintsTransform];
2735
2736 if (debugTransformLabel != null) {
2737 properties.add(DiagnosticsProperty<String>('constraints transform', debugTransformLabel));
2738 }
2739 }
2740}
2741
2742/// A widget that imposes no constraints on its child, allowing it to render
2743/// at its "natural" size.
2744///
2745/// This allows a child to render at the size it would render if it were alone
2746/// on an infinite canvas with no constraints. This container will then attempt
2747/// to adopt the same size, within the limits of its own constraints. If it ends
2748/// up with a different size, it will align the child based on [alignment].
2749/// If the box cannot expand enough to accommodate the entire child, the
2750/// child will be clipped.
2751///
2752/// In debug mode, if the child overflows the container, a warning will be
2753/// printed on the console, and black and yellow striped areas will appear where
2754/// the overflow occurs.
2755///
2756/// See also:
2757///
2758/// * [ConstrainedBox], for a box which imposes constraints on its child.
2759/// * [Align], which loosens the constraints given to the child rather than
2760/// removing them entirely.
2761/// * [Container], a convenience widget that combines common painting,
2762/// positioning, and sizing widgets.
2763/// * [OverflowBox], a widget that imposes different constraints on its child
2764/// than it gets from its parent, possibly allowing the child to overflow
2765/// the parent.
2766/// * [ConstraintsTransformBox], a widget that sizes its child using a
2767/// transformed [BoxConstraints], and shows a warning if the child overflows
2768/// in debug mode.
2769class UnconstrainedBox extends StatelessWidget {
2770 /// Creates a widget that imposes no constraints on its child, allowing it to
2771 /// render at its "natural" size. If the child overflows the parents
2772 /// constraints, a warning will be given in debug mode.
2773 const UnconstrainedBox({
2774 super.key,
2775 this.child,
2776 this.textDirection,
2777 this.alignment = Alignment.center,
2778 this.constrainedAxis,
2779 this.clipBehavior = Clip.none,
2780 });
2781
2782 /// The text direction to use when interpreting the [alignment] if it is an
2783 /// [AlignmentDirectional].
2784 final TextDirection? textDirection;
2785
2786 /// The alignment to use when laying out the child.
2787 ///
2788 /// If this is an [AlignmentDirectional], then [textDirection] must not be
2789 /// null.
2790 ///
2791 /// See also:
2792 ///
2793 /// * [Alignment] for non-[Directionality]-aware alignments.
2794 /// * [AlignmentDirectional] for [Directionality]-aware alignments.
2795 final AlignmentGeometry alignment;
2796
2797 /// The axis to retain constraints on, if any.
2798 ///
2799 /// If not set, or set to null (the default), neither axis will retain its
2800 /// constraints. If set to [Axis.vertical], then vertical constraints will
2801 /// be retained, and if set to [Axis.horizontal], then horizontal constraints
2802 /// will be retained.
2803 final Axis? constrainedAxis;
2804
2805 /// {@macro flutter.material.Material.clipBehavior}
2806 ///
2807 /// Defaults to [Clip.none].
2808 final Clip clipBehavior;
2809
2810 /// The widget below this widget in the tree.
2811 ///
2812 /// {@macro flutter.widgets.ProxyWidget.child}
2813 final Widget? child;
2814
2815 BoxConstraintsTransform _axisToTransform(Axis? constrainedAxis) {
2816 if (constrainedAxis != null) {
2817 switch (constrainedAxis) {
2818 case Axis.horizontal:
2819 return ConstraintsTransformBox.heightUnconstrained;
2820 case Axis.vertical:
2821 return ConstraintsTransformBox.widthUnconstrained;
2822 }
2823 } else {
2824 return ConstraintsTransformBox.unconstrained;
2825 }
2826 }
2827
2828 @override
2829 Widget build(BuildContext context) {
2830 return ConstraintsTransformBox(
2831 textDirection: textDirection,
2832 alignment: alignment,
2833 clipBehavior: clipBehavior,
2834 constraintsTransform: _axisToTransform(constrainedAxis),
2835 child: child,
2836 );
2837 }
2838
2839 @override
2840 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
2841 super.debugFillProperties(properties);
2842 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
2843 properties.add(EnumProperty<Axis>('constrainedAxis', constrainedAxis, defaultValue: null));
2844 properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
2845 }
2846}
2847
2848/// A widget that sizes its child to a fraction of the total available space.
2849/// For more details about the layout algorithm, see
2850/// [RenderFractionallySizedOverflowBox].
2851///
2852/// {@youtube 560 315 https://www.youtube.com/watch?v=PEsY654EGZ0}
2853///
2854/// {@tool dartpad}
2855/// This sample shows a [FractionallySizedBox] whose one child is 50% of
2856/// the box's size per the width and height factor parameters, and centered
2857/// within that box by the alignment parameter.
2858///
2859/// ** See code in examples/api/lib/widgets/basic/fractionally_sized_box.0.dart **
2860/// {@end-tool}
2861///
2862/// See also:
2863///
2864/// * [Align], which sizes itself based on its child's size and positions
2865/// the child according to an [Alignment] value.
2866/// * [OverflowBox], a widget that imposes different constraints on its child
2867/// than it gets from its parent, possibly allowing the child to overflow the
2868/// parent.
2869/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
2870class FractionallySizedBox extends SingleChildRenderObjectWidget {
2871 /// Creates a widget that sizes its child to a fraction of the total available space.
2872 ///
2873 /// If non-null, the [widthFactor] and [heightFactor] arguments must be
2874 /// non-negative.
2875 const FractionallySizedBox({
2876 super.key,
2877 this.alignment = Alignment.center,
2878 this.widthFactor,
2879 this.heightFactor,
2880 super.child,
2881 }) : assert(widthFactor == null || widthFactor >= 0.0),
2882 assert(heightFactor == null || heightFactor >= 0.0);
2883
2884 /// {@template flutter.widgets.basic.fractionallySizedBox.widthFactor}
2885 /// If non-null, the fraction of the incoming width given to the child.
2886 ///
2887 /// If non-null, the child is given a tight width constraint that is the max
2888 /// incoming width constraint multiplied by this factor.
2889 ///
2890 /// If null, the incoming width constraints are passed to the child
2891 /// unmodified.
2892 /// {@endtemplate}
2893 final double? widthFactor;
2894
2895 /// {@template flutter.widgets.basic.fractionallySizedBox.heightFactor}
2896 /// If non-null, the fraction of the incoming height given to the child.
2897 ///
2898 /// If non-null, the child is given a tight height constraint that is the max
2899 /// incoming height constraint multiplied by this factor.
2900 ///
2901 /// If null, the incoming height constraints are passed to the child
2902 /// unmodified.
2903 /// {@endtemplate}
2904 final double? heightFactor;
2905
2906 /// {@template flutter.widgets.basic.fractionallySizedBox.alignment}
2907 /// How to align the child.
2908 ///
2909 /// The x and y values of the alignment control the horizontal and vertical
2910 /// alignment, respectively. An x value of -1.0 means that the left edge of
2911 /// the child is aligned with the left edge of the parent whereas an x value
2912 /// of 1.0 means that the right edge of the child is aligned with the right
2913 /// edge of the parent. Other values interpolate (and extrapolate) linearly.
2914 /// For example, a value of 0.0 means that the center of the child is aligned
2915 /// with the center of the parent.
2916 ///
2917 /// Defaults to [Alignment.center].
2918 ///
2919 /// See also:
2920 ///
2921 /// * [Alignment], a class with convenient constants typically used to
2922 /// specify an [AlignmentGeometry].
2923 /// * [AlignmentDirectional], like [Alignment] for specifying alignments
2924 /// relative to text direction.
2925 /// {@endtemplate}
2926 final AlignmentGeometry alignment;
2927
2928 @override
2929 RenderFractionallySizedOverflowBox createRenderObject(BuildContext context) {
2930 return RenderFractionallySizedOverflowBox(
2931 alignment: alignment,
2932 widthFactor: widthFactor,
2933 heightFactor: heightFactor,
2934 textDirection: Directionality.maybeOf(context),
2935 );
2936 }
2937
2938 @override
2939 void updateRenderObject(BuildContext context, RenderFractionallySizedOverflowBox renderObject) {
2940 renderObject
2941 ..alignment = alignment
2942 ..widthFactor = widthFactor
2943 ..heightFactor = heightFactor
2944 ..textDirection = Directionality.maybeOf(context);
2945 }
2946
2947 @override
2948 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
2949 super.debugFillProperties(properties);
2950 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
2951 properties.add(DoubleProperty('widthFactor', widthFactor, defaultValue: null));
2952 properties.add(DoubleProperty('heightFactor', heightFactor, defaultValue: null));
2953 }
2954}
2955
2956/// A box that limits its size only when it's unconstrained.
2957///
2958/// If this widget's maximum width is unconstrained then its child's width is
2959/// limited to [maxWidth]. Similarly, if this widget's maximum height is
2960/// unconstrained then its child's height is limited to [maxHeight].
2961///
2962/// This has the effect of giving the child a natural dimension in unbounded
2963/// environments. For example, by providing a [maxHeight] to a widget that
2964/// normally tries to be as big as possible, the widget will normally size
2965/// itself to fit its parent, but when placed in a vertical list, it will take
2966/// on the given height.
2967///
2968/// This is useful when composing widgets that normally try to match their
2969/// parents' size, so that they behave reasonably in lists (which are
2970/// unbounded).
2971///
2972/// {@youtube 560 315 https://www.youtube.com/watch?v=uVki2CIzBTs}
2973///
2974/// See also:
2975///
2976/// * [ConstrainedBox], which applies its constraints in all cases, not just
2977/// when the incoming constraints are unbounded.
2978/// * [SizedBox], which lets you specify tight constraints by explicitly
2979/// specifying the height or width.
2980/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
2981class LimitedBox extends SingleChildRenderObjectWidget {
2982 /// Creates a box that limits its size only when it's unconstrained.
2983 ///
2984 /// The [maxWidth] and [maxHeight] arguments must not be negative.
2985 const LimitedBox({
2986 super.key,
2987 this.maxWidth = double.infinity,
2988 this.maxHeight = double.infinity,
2989 super.child,
2990 }) : assert(maxWidth >= 0.0),
2991 assert(maxHeight >= 0.0);
2992
2993 /// The maximum width limit to apply in the absence of a
2994 /// [BoxConstraints.maxWidth] constraint.
2995 final double maxWidth;
2996
2997 /// The maximum height limit to apply in the absence of a
2998 /// [BoxConstraints.maxHeight] constraint.
2999 final double maxHeight;
3000
3001 @override
3002 RenderLimitedBox createRenderObject(BuildContext context) {
3003 return RenderLimitedBox(
3004 maxWidth: maxWidth,
3005 maxHeight: maxHeight,
3006 );
3007 }
3008
3009 @override
3010 void updateRenderObject(BuildContext context, RenderLimitedBox renderObject) {
3011 renderObject
3012 ..maxWidth = maxWidth
3013 ..maxHeight = maxHeight;
3014 }
3015
3016 @override
3017 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
3018 super.debugFillProperties(properties);
3019 properties.add(DoubleProperty('maxWidth', maxWidth, defaultValue: double.infinity));
3020 properties.add(DoubleProperty('maxHeight', maxHeight, defaultValue: double.infinity));
3021 }
3022}
3023
3024/// A widget that imposes different constraints on its child than it gets
3025/// from its parent, possibly allowing the child to overflow the parent.
3026///
3027/// {@tool dartpad}
3028/// This example shows how an [OverflowBox] is used, and what its effect is.
3029///
3030/// ** See code in examples/api/lib/widgets/basic/overflowbox.0.dart **
3031/// {@end-tool}
3032///
3033/// See also:
3034///
3035/// * [RenderConstrainedOverflowBox] for details about how [OverflowBox] is
3036/// rendered.
3037/// * [SizedOverflowBox], a widget that is a specific size but passes its
3038/// original constraints through to its child, which may then overflow.
3039/// * [ConstrainedBox], a widget that imposes additional constraints on its
3040/// child.
3041/// * [UnconstrainedBox], a container that tries to let its child draw without
3042/// constraints.
3043/// * [SizedBox], a box with a specified size.
3044/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
3045class OverflowBox extends SingleChildRenderObjectWidget {
3046 /// Creates a widget that lets its child overflow itself.
3047 const OverflowBox({
3048 super.key,
3049 this.alignment = Alignment.center,
3050 this.minWidth,
3051 this.maxWidth,
3052 this.minHeight,
3053 this.maxHeight,
3054 this.fit = OverflowBoxFit.max,
3055 super.child,
3056 });
3057
3058 /// How to align the child.
3059 ///
3060 /// The x and y values of the alignment control the horizontal and vertical
3061 /// alignment, respectively. An x value of -1.0 means that the left edge of
3062 /// the child is aligned with the left edge of the parent whereas an x value
3063 /// of 1.0 means that the right edge of the child is aligned with the right
3064 /// edge of the parent. Other values interpolate (and extrapolate) linearly.
3065 /// For example, a value of 0.0 means that the center of the child is aligned
3066 /// with the center of the parent.
3067 ///
3068 /// Defaults to [Alignment.center].
3069 ///
3070 /// See also:
3071 ///
3072 /// * [Alignment], a class with convenient constants typically used to
3073 /// specify an [AlignmentGeometry].
3074 /// * [AlignmentDirectional], like [Alignment] for specifying alignments
3075 /// relative to text direction.
3076 final AlignmentGeometry alignment;
3077
3078 /// The minimum width constraint to give the child. Set this to null (the
3079 /// default) to use the constraint from the parent instead.
3080 final double? minWidth;
3081
3082 /// The maximum width constraint to give the child. Set this to null (the
3083 /// default) to use the constraint from the parent instead.
3084 final double? maxWidth;
3085
3086 /// The minimum height constraint to give the child. Set this to null (the
3087 /// default) to use the constraint from the parent instead.
3088 final double? minHeight;
3089
3090 /// The maximum height constraint to give the child. Set this to null (the
3091 /// default) to use the constraint from the parent instead.
3092 final double? maxHeight;
3093
3094 /// The way to size the render object.
3095 ///
3096 /// This only affects scenario when the child does not indeed overflow.
3097 /// If set to [OverflowBoxFit.deferToChild], the render object will size itself to
3098 /// match the size of its child within the constraints of its parent or be
3099 /// as small as the parent allows if no child is set. If set to
3100 /// [OverflowBoxFit.max] (the default), the render object will size itself
3101 /// to be as large as the parent allows.
3102 final OverflowBoxFit fit;
3103
3104 @override
3105 RenderConstrainedOverflowBox createRenderObject(BuildContext context) {
3106 return RenderConstrainedOverflowBox(
3107 alignment: alignment,
3108 minWidth: minWidth,
3109 maxWidth: maxWidth,
3110 minHeight: minHeight,
3111 maxHeight: maxHeight,
3112 fit: fit,
3113 textDirection: Directionality.maybeOf(context),
3114 );
3115 }
3116
3117 @override
3118 void updateRenderObject(BuildContext context, RenderConstrainedOverflowBox renderObject) {
3119 renderObject
3120 ..alignment = alignment
3121 ..minWidth = minWidth
3122 ..maxWidth = maxWidth
3123 ..minHeight = minHeight
3124 ..maxHeight = maxHeight
3125 ..fit = fit
3126 ..textDirection = Directionality.maybeOf(context);
3127 }
3128
3129 @override
3130 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
3131 super.debugFillProperties(properties);
3132 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
3133 properties.add(DoubleProperty('minWidth', minWidth, defaultValue: null));
3134 properties.add(DoubleProperty('maxWidth', maxWidth, defaultValue: null));
3135 properties.add(DoubleProperty('minHeight', minHeight, defaultValue: null));
3136 properties.add(DoubleProperty('maxHeight', maxHeight, defaultValue: null));
3137 properties.add(EnumProperty<OverflowBoxFit>('fit', fit));
3138 }
3139}
3140
3141/// A widget that is a specific size but passes its original constraints
3142/// through to its child, which may then overflow.
3143///
3144/// See also:
3145///
3146/// * [OverflowBox], A widget that imposes different constraints on its child
3147/// than it gets from its parent, possibly allowing the child to overflow the
3148/// parent.
3149/// * [ConstrainedBox], a widget that imposes additional constraints on its
3150/// child.
3151/// * [UnconstrainedBox], a container that tries to let its child draw without
3152/// constraints.
3153/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
3154class SizedOverflowBox extends SingleChildRenderObjectWidget {
3155 /// Creates a widget of a given size that lets its child overflow.
3156 const SizedOverflowBox({
3157 super.key,
3158 required this.size,
3159 this.alignment = Alignment.center,
3160 super.child,
3161 });
3162
3163 /// How to align the child.
3164 ///
3165 /// The x and y values of the alignment control the horizontal and vertical
3166 /// alignment, respectively. An x value of -1.0 means that the left edge of
3167 /// the child is aligned with the left edge of the parent whereas an x value
3168 /// of 1.0 means that the right edge of the child is aligned with the right
3169 /// edge of the parent. Other values interpolate (and extrapolate) linearly.
3170 /// For example, a value of 0.0 means that the center of the child is aligned
3171 /// with the center of the parent.
3172 ///
3173 /// Defaults to [Alignment.center].
3174 ///
3175 /// See also:
3176 ///
3177 /// * [Alignment], a class with convenient constants typically used to
3178 /// specify an [AlignmentGeometry].
3179 /// * [AlignmentDirectional], like [Alignment] for specifying alignments
3180 /// relative to text direction.
3181 final AlignmentGeometry alignment;
3182
3183 /// The size this widget should attempt to be.
3184 final Size size;
3185
3186 @override
3187 RenderSizedOverflowBox createRenderObject(BuildContext context) {
3188 return RenderSizedOverflowBox(
3189 alignment: alignment,
3190 requestedSize: size,
3191 textDirection: Directionality.of(context),
3192 );
3193 }
3194
3195 @override
3196 void updateRenderObject(BuildContext context, RenderSizedOverflowBox renderObject) {
3197 renderObject
3198 ..alignment = alignment
3199 ..requestedSize = size
3200 ..textDirection = Directionality.of(context);
3201 }
3202
3203 @override
3204 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
3205 super.debugFillProperties(properties);
3206 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
3207 properties.add(DiagnosticsProperty<Size>('size', size, defaultValue: null));
3208 }
3209}
3210
3211/// A widget that lays the child out as if it was in the tree, but without
3212/// painting anything, without making the child available for hit testing, and
3213/// without taking any room in the parent.
3214///
3215/// Offstage children are still active: they can receive focus and have keyboard
3216/// input directed to them.
3217///
3218/// Animations continue to run in offstage children, and therefore use battery
3219/// and CPU time, regardless of whether the animations end up being visible.
3220///
3221/// [Offstage] can be used to measure the dimensions of a widget without
3222/// bringing it on screen (yet). To hide a widget from view while it is not
3223/// needed, prefer removing the widget from the tree entirely rather than
3224/// keeping it alive in an [Offstage] subtree.
3225///
3226/// {@tool dartpad}
3227/// This example shows a [FlutterLogo] widget when the `_offstage` member field
3228/// is false, and hides it without any room in the parent when it is true. When
3229/// offstage, this app displays a button to get the logo size, which will be
3230/// displayed in a [SnackBar].
3231///
3232/// ** See code in examples/api/lib/widgets/basic/offstage.0.dart **
3233/// {@end-tool}
3234///
3235/// See also:
3236///
3237/// * [Visibility], which can hide a child more efficiently (albeit less
3238/// subtly).
3239/// * [TickerMode], which can be used to disable animations in a subtree.
3240/// * [SliverOffstage], the sliver version of this widget.
3241/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
3242class Offstage extends SingleChildRenderObjectWidget {
3243 /// Creates a widget that visually hides its child.
3244 const Offstage({ super.key, this.offstage = true, super.child });
3245
3246 /// Whether the child is hidden from the rest of the tree.
3247 ///
3248 /// If true, the child is laid out as if it was in the tree, but without
3249 /// painting anything, without making the child available for hit testing, and
3250 /// without taking any room in the parent.
3251 ///
3252 /// Offstage children are still active: they can receive focus and have keyboard
3253 /// input directed to them.
3254 ///
3255 /// Animations continue to run in offstage children, and therefore use battery
3256 /// and CPU time, regardless of whether the animations end up being visible.
3257 ///
3258 /// If false, the child is included in the tree as normal.
3259 final bool offstage;
3260
3261 @override
3262 RenderOffstage createRenderObject(BuildContext context) => RenderOffstage(offstage: offstage);
3263
3264 @override
3265 void updateRenderObject(BuildContext context, RenderOffstage renderObject) {
3266 renderObject.offstage = offstage;
3267 }
3268
3269 @override
3270 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
3271 super.debugFillProperties(properties);
3272 properties.add(DiagnosticsProperty<bool>('offstage', offstage));
3273 }
3274
3275 @override
3276 SingleChildRenderObjectElement createElement() => _OffstageElement(this);
3277}
3278
3279class _OffstageElement extends SingleChildRenderObjectElement {
3280 _OffstageElement(Offstage super.widget);
3281
3282 @override
3283 void debugVisitOnstageChildren(ElementVisitor visitor) {
3284 if (!(widget as Offstage).offstage) {
3285 super.debugVisitOnstageChildren(visitor);
3286 }
3287 }
3288}
3289
3290/// A widget that attempts to size the child to a specific aspect ratio.
3291///
3292/// The aspect ratio is expressed as a ratio of width to height. For example, a
3293/// 16:9 width:height aspect ratio would have a value of 16.0/9.0.
3294///
3295/// {@youtube 560 315 https://www.youtube.com/watch?v=XcnP3_mO_Ms}
3296///
3297/// The [AspectRatio] widget uses a finite iterative process to compute the
3298/// appropriate constraints for the child, and then lays the child out a single
3299/// time with those constraints. This iterative process is efficient and does
3300/// not require multiple layout passes.
3301///
3302/// The widget first tries the largest width permitted by the layout
3303/// constraints, and determines the height of the widget by applying the given
3304/// aspect ratio to the width, expressed as a ratio of width to height.
3305///
3306/// If the maximum width is infinite, the initial width is determined
3307/// by applying the aspect ratio to the maximum height instead.
3308///
3309/// The widget then examines if the computed dimensions are compatible with the
3310/// parent's constraints; if not, the dimensions are recomputed a second time,
3311/// taking those constraints into account.
3312///
3313/// If the widget does not find a feasible size after consulting each
3314/// constraint, the widget will eventually select a size for the child that
3315/// meets the layout constraints but fails to meet the aspect ratio constraints.
3316///
3317/// {@tool dartpad}
3318/// This examples shows how [AspectRatio] sets the width when its parent's width
3319/// constraint is infinite. Since the parent's allowed height is a fixed value,
3320/// the actual width is determined via the given [aspectRatio].
3321///
3322/// In this example, the height is fixed at 100.0 and the aspect ratio is set to
3323/// 16 / 9, making the width 100.0 / 9 * 16.
3324///
3325/// ** See code in examples/api/lib/widgets/basic/aspect_ratio.0.dart **
3326/// {@end-tool}
3327///
3328/// {@tool dartpad}
3329/// This second example uses an aspect ratio of 2.0, and layout constraints that
3330/// require the width to be between 0.0 and 100.0, and the height to be between
3331/// 0.0 and 100.0. The widget selects a width of 100.0 (the biggest allowed) and
3332/// a height of 50.0 (to match the aspect ratio).
3333///
3334/// ** See code in examples/api/lib/widgets/basic/aspect_ratio.1.dart **
3335/// {@end-tool}
3336///
3337/// {@tool dartpad}
3338/// This third example is similar to the second, but with the aspect ratio set
3339/// to 0.5. The widget still selects a width of 100.0 (the biggest allowed), and
3340/// attempts to use a height of 200.0. Unfortunately, that violates the
3341/// constraints because the child can be at most 100.0 pixels tall. The widget
3342/// will then take that value and apply the aspect ratio again to obtain a width
3343/// of 50.0. That width is permitted by the constraints and the child receives a
3344/// width of 50.0 and a height of 100.0. If the width were not permitted, the
3345/// widget would continue iterating through the constraints.
3346///
3347/// ** See code in examples/api/lib/widgets/basic/aspect_ratio.2.dart **
3348/// {@end-tool}
3349///
3350/// ## Setting the aspect ratio in unconstrained situations
3351///
3352/// When using a widget such as [FittedBox], the constraints are unbounded. This
3353/// results in [AspectRatio] being unable to find a suitable set of constraints
3354/// to apply. In that situation, consider explicitly setting a size using
3355/// [SizedBox] instead of setting the aspect ratio using [AspectRatio]. The size
3356/// is then scaled appropriately by the [FittedBox].
3357///
3358/// See also:
3359///
3360/// * [Align], a widget that aligns its child within itself and optionally
3361/// sizes itself based on the child's size.
3362/// * [ConstrainedBox], a widget that imposes additional constraints on its
3363/// child.
3364/// * [UnconstrainedBox], a container that tries to let its child draw without
3365/// constraints.
3366/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
3367class AspectRatio extends SingleChildRenderObjectWidget {
3368 /// Creates a widget with a specific aspect ratio.
3369 ///
3370 /// The [aspectRatio] argument must be a finite number greater than zero.
3371 const AspectRatio({
3372 super.key,
3373 required this.aspectRatio,
3374 super.child,
3375 }) : assert(aspectRatio > 0.0);
3376
3377 /// The aspect ratio to attempt to use.
3378 ///
3379 /// The aspect ratio is expressed as a ratio of width to height. For example,
3380 /// a 16:9 width:height aspect ratio would have a value of 16.0/9.0.
3381 final double aspectRatio;
3382
3383 @override
3384 RenderAspectRatio createRenderObject(BuildContext context) => RenderAspectRatio(aspectRatio: aspectRatio);
3385
3386 @override
3387 void updateRenderObject(BuildContext context, RenderAspectRatio renderObject) {
3388 renderObject.aspectRatio = aspectRatio;
3389 }
3390
3391 @override
3392 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
3393 super.debugFillProperties(properties);
3394 properties.add(DoubleProperty('aspectRatio', aspectRatio));
3395 }
3396}
3397
3398/// A widget that sizes its child to the child's maximum intrinsic width.
3399///
3400/// This class is useful, for example, when unlimited width is available and
3401/// you would like a child that would otherwise attempt to expand infinitely to
3402/// instead size itself to a more reasonable width.
3403///
3404/// The constraints that this widget passes to its child will adhere to the
3405/// parent's constraints, so if the constraints are not large enough to satisfy
3406/// the child's maximum intrinsic width, then the child will get less width
3407/// than it otherwise would. Likewise, if the minimum width constraint is
3408/// larger than the child's maximum intrinsic width, the child will be given
3409/// more width than it otherwise would.
3410///
3411/// If [stepWidth] is non-null, the child's width will be snapped to a multiple
3412/// of the [stepWidth]. Similarly, if [stepHeight] is non-null, the child's
3413/// height will be snapped to a multiple of the [stepHeight].
3414///
3415/// This class is relatively expensive, because it adds a speculative layout
3416/// pass before the final layout phase. Avoid using it where possible. In the
3417/// worst case, this widget can result in a layout that is O(N²) in the depth of
3418/// the tree.
3419///
3420/// See also:
3421///
3422/// * [Align], a widget that aligns its child within itself. This can be used
3423/// to loosen the constraints passed to the [RenderIntrinsicWidth],
3424/// allowing the [RenderIntrinsicWidth]'s child to be smaller than that of
3425/// its parent.
3426/// * [Row], which when used with [CrossAxisAlignment.stretch] can be used
3427/// to loosen just the width constraints that are passed to the
3428/// [RenderIntrinsicWidth], allowing the [RenderIntrinsicWidth]'s child's
3429/// width to be smaller than that of its parent.
3430/// * [The catalog of layout widgets](https://flutter.dev/widgets/layout/).
3431class IntrinsicWidth extends SingleChildRenderObjectWidget {
3432 /// Creates a widget that sizes its child to the child's intrinsic width.
3433 ///
3434 /// This class is relatively expensive. Avoid using it where possible.
3435 const IntrinsicWidth({ super.key, this.stepWidth, this.stepHeight, super.child })
3436 : assert(stepWidth == null || stepWidth >= 0.0),
3437 assert(stepHeight == null || stepHeight >= 0.0);
3438
3439 /// If non-null, force the child's width to be a multiple of this value.
3440 ///
3441 /// If null or 0.0 the child's width will be the same as its maximum
3442 /// intrinsic width.
3443 ///
3444 /// This value must not be negative.
3445 ///
3446 /// See also:
3447 ///
3448 /// * [RenderBox.getMaxIntrinsicWidth], which defines a widget's max
3449 /// intrinsic width in general.
3450 final double? stepWidth;
3451
3452 /// If non-null, force the child's height to be a multiple of this value.
3453 ///
3454 /// If null or 0.0 the child's height will not be constrained.
3455 ///
3456 /// This value must not be negative.
3457 final double? stepHeight;
3458
3459 double? get _stepWidth => stepWidth == 0.0 ? null : stepWidth;
3460 double? get _stepHeight => stepHeight == 0.0 ? null : stepHeight;
3461
3462 @override
3463 RenderIntrinsicWidth createRenderObject(BuildContext context) {
3464 return RenderIntrinsicWidth(stepWidth: _stepWidth, stepHeight: _stepHeight);
3465 }
3466
3467 @override
3468 void updateRenderObject(BuildContext context, RenderIntrinsicWidth renderObject) {
3469 renderObject
3470 ..stepWidth = _stepWidth
3471 ..stepHeight = _stepHeight;
3472 }
3473}
3474
3475/// A widget that sizes its child to the child's intrinsic height.
3476///
3477/// This class is useful, for example, when unlimited height is available and
3478/// you would like a child that would otherwise attempt to expand infinitely to
3479/// instead size itself to a more reasonable height.
3480///
3481/// The constraints that this widget passes to its child will adhere to the
3482/// parent's constraints, so if the constraints are not large enough to satisfy
3483/// the child's maximum intrinsic height, then the child will get less height
3484/// than it otherwise would. Likewise, if the minimum height constraint is
3485/// larger than the child's maximum intrinsic height, the child will be given
3486/// more height than it otherwise would.
3487///
3488/// This class is relatively expensive, because it adds a speculative layout
3489/// pass before the final layout phase. Avoid using it where possible. In the
3490/// worst case, this widget can result in a layout that is O(N²) in the depth of
3491/// the tree.
3492///
3493/// See also:
3494///
3495/// * [Align], a widget that aligns its child within itself. This can be used
3496/// to loosen the constraints passed to the [RenderIntrinsicHeight],
3497/// allowing the [RenderIntrinsicHeight]'s child to be smaller than that of
3498/// its parent.
3499/// * [Column], which when used with [CrossAxisAlignment.stretch] can be used
3500/// to loosen just the height constraints that are passed to the
3501/// [RenderIntrinsicHeight], allowing the [RenderIntrinsicHeight]'s child's
3502/// height to be smaller than that of its parent.
3503/// * [The catalog of layout widgets](https://flutter.dev/widgets/layout/).
3504class IntrinsicHeight extends SingleChildRenderObjectWidget {
3505 /// Creates a widget that sizes its child to the child's intrinsic height.
3506 ///
3507 /// This class is relatively expensive. Avoid using it where possible.
3508 const IntrinsicHeight({ super.key, super.child });
3509
3510 @override
3511 RenderIntrinsicHeight createRenderObject(BuildContext context) => RenderIntrinsicHeight();
3512}
3513
3514/// A widget that positions its child according to the child's baseline.
3515///
3516/// This widget shifts the child down such that the child's baseline (or the
3517/// bottom of the child, if the child has no baseline) is [baseline]
3518/// logical pixels below the top of this box, then sizes this box to
3519/// contain the child. If [baseline] is less than the distance from
3520/// the top of the child to the baseline of the child, then the child
3521/// is top-aligned instead.
3522///
3523/// {@youtube 560 315 https://www.youtube.com/watch?v=8ZaFk0yvNlI}
3524///
3525/// See also:
3526///
3527/// * [Align], a widget that aligns its child within itself and optionally
3528/// sizes itself based on the child's size.
3529/// * [Center], a widget that centers its child within itself.
3530/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
3531class Baseline extends SingleChildRenderObjectWidget {
3532 /// Creates a widget that positions its child according to the child's baseline.
3533 const Baseline({
3534 super.key,
3535 required this.baseline,
3536 required this.baselineType,
3537 super.child,
3538 });
3539
3540 /// The number of logical pixels from the top of this box at which to position
3541 /// the child's baseline.
3542 final double baseline;
3543
3544 /// The type of baseline to use for positioning the child.
3545 final TextBaseline baselineType;
3546
3547 @override
3548 RenderBaseline createRenderObject(BuildContext context) {
3549 return RenderBaseline(baseline: baseline, baselineType: baselineType);
3550 }
3551
3552 @override
3553 void updateRenderObject(BuildContext context, RenderBaseline renderObject) {
3554 renderObject
3555 ..baseline = baseline
3556 ..baselineType = baselineType;
3557 }
3558}
3559
3560/// A widget that causes the parent to ignore the [child] for the purposes
3561/// of baseline alignment.
3562///
3563/// See also:
3564///
3565/// * [Baseline], a widget that positions a child relative to a baseline.
3566class IgnoreBaseline extends SingleChildRenderObjectWidget {
3567 /// Creates a widget that ignores the child for baseline alignment purposes.
3568 const IgnoreBaseline({
3569 super.key,
3570 super.child,
3571 });
3572
3573 @override
3574 RenderIgnoreBaseline createRenderObject(BuildContext context) {
3575 return RenderIgnoreBaseline();
3576 }
3577}
3578
3579
3580// SLIVERS
3581
3582/// A sliver that contains a single box widget.
3583///
3584/// Slivers are special-purpose widgets that can be combined using a
3585/// [CustomScrollView] to create custom scroll effects. A [SliverToBoxAdapter]
3586/// is a basic sliver that creates a bridge back to one of the usual box-based
3587/// widgets.
3588///
3589/// _To learn more about slivers, see [CustomScrollView.slivers]._
3590///
3591/// Rather than using multiple [SliverToBoxAdapter] widgets to display multiple
3592/// box widgets in a [CustomScrollView], consider using [SliverList],
3593/// [SliverFixedExtentList], [SliverPrototypeExtentList], or [SliverGrid],
3594/// which are more efficient because they instantiate only those children that
3595/// are actually visible through the scroll view's viewport.
3596///
3597/// See also:
3598///
3599/// * [CustomScrollView], which displays a scrollable list of slivers.
3600/// * [SliverList], which displays multiple box widgets in a linear array.
3601/// * [SliverFixedExtentList], which displays multiple box widgets with the
3602/// same main-axis extent in a linear array.
3603/// * [SliverPrototypeExtentList], which displays multiple box widgets with the
3604/// same main-axis extent as a prototype item, in a linear array.
3605/// * [SliverGrid], which displays multiple box widgets in arbitrary positions.
3606class SliverToBoxAdapter extends SingleChildRenderObjectWidget {
3607 /// Creates a sliver that contains a single box widget.
3608 const SliverToBoxAdapter({
3609 super.key,
3610 super.child,
3611 });
3612
3613 @override
3614 RenderSliverToBoxAdapter createRenderObject(BuildContext context) => RenderSliverToBoxAdapter();
3615}
3616
3617/// A sliver that applies padding on each side of another sliver.
3618///
3619/// Slivers are special-purpose widgets that can be combined using a
3620/// [CustomScrollView] to create custom scroll effects. A [SliverPadding]
3621/// is a basic sliver that insets another sliver by applying padding on each
3622/// side.
3623///
3624/// {@macro flutter.rendering.RenderSliverEdgeInsetsPadding}
3625///
3626/// See also:
3627///
3628/// * [CustomScrollView], which displays a scrollable list of slivers.
3629/// * [Padding], the box version of this widget.
3630class SliverPadding extends SingleChildRenderObjectWidget {
3631 /// Creates a sliver that applies padding on each side of another sliver.
3632 const SliverPadding({
3633 super.key,
3634 required this.padding,
3635 Widget? sliver,
3636 }) : super(child: sliver);
3637
3638 /// The amount of space by which to inset the child sliver.
3639 final EdgeInsetsGeometry padding;
3640
3641 @override
3642 RenderSliverPadding createRenderObject(BuildContext context) {
3643 return RenderSliverPadding(
3644 padding: padding,
3645 textDirection: Directionality.of(context),
3646 );
3647 }
3648
3649 @override
3650 void updateRenderObject(BuildContext context, RenderSliverPadding renderObject) {
3651 renderObject
3652 ..padding = padding
3653 ..textDirection = Directionality.of(context);
3654 }
3655
3656 @override
3657 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
3658 super.debugFillProperties(properties);
3659 properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding));
3660 }
3661}
3662
3663
3664// LAYOUT NODES
3665
3666/// Returns the [AxisDirection] in the given [Axis] in the current
3667/// [Directionality] (or the reverse if `reverse` is true).
3668///
3669/// If `axis` is [Axis.vertical], this function returns [AxisDirection.down]
3670/// unless `reverse` is true, in which case this function returns
3671/// [AxisDirection.up].
3672///
3673/// If `axis` is [Axis.horizontal], this function checks the current
3674/// [Directionality]. If the current [Directionality] is right-to-left, then
3675/// this function returns [AxisDirection.left] (unless `reverse` is true, in
3676/// which case it returns [AxisDirection.right]). Similarly, if the current
3677/// [Directionality] is left-to-right, then this function returns
3678/// [AxisDirection.right] (unless `reverse` is true, in which case it returns
3679/// [AxisDirection.left]).
3680///
3681/// This function is used by a number of scrolling widgets (e.g., [ListView],
3682/// [GridView], [PageView], and [SingleChildScrollView]) as well as [ListBody]
3683/// to translate their [Axis] and `reverse` properties into a concrete
3684/// [AxisDirection].
3685AxisDirection getAxisDirectionFromAxisReverseAndDirectionality(
3686 BuildContext context,
3687 Axis axis,
3688 bool reverse,
3689) {
3690 switch (axis) {
3691 case Axis.horizontal:
3692 assert(debugCheckHasDirectionality(context));
3693 final TextDirection textDirection = Directionality.of(context);
3694 final AxisDirection axisDirection = textDirectionToAxisDirection(textDirection);
3695 return reverse ? flipAxisDirection(axisDirection) : axisDirection;
3696 case Axis.vertical:
3697 return reverse ? AxisDirection.up : AxisDirection.down;
3698 }
3699}
3700
3701/// A widget that arranges its children sequentially along a given axis, forcing
3702/// them to the dimension of the parent in the other axis.
3703///
3704/// This widget is rarely used directly. Instead, consider using [ListView],
3705/// which combines a similar layout algorithm with scrolling behavior, or
3706/// [Column], which gives you more flexible control over the layout of a
3707/// vertical set of boxes.
3708///
3709/// See also:
3710///
3711/// * [RenderListBody], which implements this layout algorithm and the
3712/// documentation for which describes some of its subtleties.
3713/// * [SingleChildScrollView], which is sometimes used with [ListBody] to
3714/// make the contents scrollable.
3715/// * [Column] and [Row], which implement a more elaborate version of
3716/// this layout algorithm (at the cost of being slightly less efficient).
3717/// * [ListView], which implements an efficient scrolling version of this
3718/// layout algorithm.
3719/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
3720class ListBody extends MultiChildRenderObjectWidget {
3721 /// Creates a layout widget that arranges its children sequentially along a
3722 /// given axis.
3723 ///
3724 /// By default, the [mainAxis] is [Axis.vertical].
3725 const ListBody({
3726 super.key,
3727 this.mainAxis = Axis.vertical,
3728 this.reverse = false,
3729 super.children,
3730 });
3731
3732 /// The direction to use as the main axis.
3733 final Axis mainAxis;
3734
3735 /// Whether the list body positions children in the reading direction.
3736 ///
3737 /// For example, if the reading direction is left-to-right and
3738 /// [mainAxis] is [Axis.horizontal], then the list body positions children
3739 /// from left to right when [reverse] is false and from right to left when
3740 /// [reverse] is true.
3741 ///
3742 /// Similarly, if [mainAxis] is [Axis.vertical], then the list body positions
3743 /// from top to bottom when [reverse] is false and from bottom to top when
3744 /// [reverse] is true.
3745 ///
3746 /// Defaults to false.
3747 final bool reverse;
3748
3749 AxisDirection _getDirection(BuildContext context) {
3750 return getAxisDirectionFromAxisReverseAndDirectionality(context, mainAxis, reverse);
3751 }
3752
3753 @override
3754 RenderListBody createRenderObject(BuildContext context) {
3755 return RenderListBody(axisDirection: _getDirection(context));
3756 }
3757
3758 @override
3759 void updateRenderObject(BuildContext context, RenderListBody renderObject) {
3760 renderObject.axisDirection = _getDirection(context);
3761 }
3762}
3763
3764/// A widget that positions its children relative to the edges of its box.
3765///
3766/// This class is useful if you want to overlap several children in a simple
3767/// way, for example having some text and an image, overlaid with a gradient and
3768/// a button attached to the bottom.
3769///
3770/// {@youtube 560 315 https://www.youtube.com/watch?v=liEGSeD3Zt8}
3771///
3772/// Each child of a [Stack] widget is either _positioned_ or _non-positioned_.
3773/// Positioned children are those wrapped in a [Positioned] widget that has at
3774/// least one non-null property. The stack sizes itself to contain all the
3775/// non-positioned children, which are positioned according to [alignment]
3776/// (which defaults to the top-left corner in left-to-right environments and the
3777/// top-right corner in right-to-left environments). The positioned children are
3778/// then placed relative to the stack according to their top, right, bottom, and
3779/// left properties.
3780///
3781/// The stack paints its children in order with the first child being at the
3782/// bottom. If you want to change the order in which the children paint, you
3783/// can rebuild the stack with the children in the new order. If you reorder
3784/// the children in this way, consider giving the children non-null keys.
3785/// These keys will cause the framework to move the underlying objects for
3786/// the children to their new locations rather than recreate them at their
3787/// new location.
3788///
3789/// For more details about the stack layout algorithm, see [RenderStack].
3790///
3791/// If you want to lay a number of children out in a particular pattern, or if
3792/// you want to make a custom layout manager, you probably want to use
3793/// [CustomMultiChildLayout] instead. In particular, when using a [Stack] you
3794/// can't position children relative to their size or the stack's own size.
3795///
3796/// {@tool snippet}
3797///
3798/// Using a [Stack] you can position widgets over one another.
3799///
3800/// ![The sample creates a blue box that overlaps a larger green box, which itself overlaps an even larger red box.](https://flutter.github.io/assets-for-api-docs/assets/widgets/stack.png)
3801///
3802/// ```dart
3803/// Stack(
3804/// children: <Widget>[
3805/// Container(
3806/// width: 100,
3807/// height: 100,
3808/// color: Colors.red,
3809/// ),
3810/// Container(
3811/// width: 90,
3812/// height: 90,
3813/// color: Colors.green,
3814/// ),
3815/// Container(
3816/// width: 80,
3817/// height: 80,
3818/// color: Colors.blue,
3819/// ),
3820/// ],
3821/// )
3822/// ```
3823/// {@end-tool}
3824///
3825/// {@tool snippet}
3826///
3827/// This example shows how [Stack] can be used to enhance text visibility
3828/// by adding gradient backdrops.
3829///
3830/// ![The gradient fades from transparent to dark grey at the bottom, with white text on top of the darker portion.](https://flutter.github.io/assets-for-api-docs/assets/widgets/stack_with_gradient.png)
3831///
3832/// ```dart
3833/// SizedBox(
3834/// width: 250,
3835/// height: 250,
3836/// child: Stack(
3837/// children: <Widget>[
3838/// Container(
3839/// width: 250,
3840/// height: 250,
3841/// color: Colors.white,
3842/// ),
3843/// Container(
3844/// padding: const EdgeInsets.all(5.0),
3845/// alignment: Alignment.bottomCenter,
3846/// decoration: BoxDecoration(
3847/// gradient: LinearGradient(
3848/// begin: Alignment.topCenter,
3849/// end: Alignment.bottomCenter,
3850/// colors: <Color>[
3851/// Colors.black.withAlpha(0),
3852/// Colors.black12,
3853/// Colors.black45
3854/// ],
3855/// ),
3856/// ),
3857/// child: const Text(
3858/// 'Foreground Text',
3859/// style: TextStyle(color: Colors.white, fontSize: 20.0),
3860/// ),
3861/// ),
3862/// ],
3863/// ),
3864/// )
3865/// ```
3866/// {@end-tool}
3867///
3868/// See also:
3869///
3870/// * [Align], which sizes itself based on its child's size and positions
3871/// the child according to an [Alignment] value.
3872/// * [CustomSingleChildLayout], which uses a delegate to control the layout of
3873/// a single child.
3874/// * [CustomMultiChildLayout], which uses a delegate to position multiple
3875/// children.
3876/// * [Flow], which provides paint-time control of its children using transform
3877/// matrices.
3878/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
3879class Stack extends MultiChildRenderObjectWidget {
3880 /// Creates a stack layout widget.
3881 ///
3882 /// By default, the non-positioned children of the stack are aligned by their
3883 /// top left corners.
3884 const Stack({
3885 super.key,
3886 this.alignment = AlignmentDirectional.topStart,
3887 this.textDirection,
3888 this.fit = StackFit.loose,
3889 this.clipBehavior = Clip.hardEdge,
3890 super.children,
3891 });
3892
3893 /// How to align the non-positioned and partially-positioned children in the
3894 /// stack.
3895 ///
3896 /// The non-positioned children are placed relative to each other such that
3897 /// the points determined by [alignment] are co-located. For example, if the
3898 /// [alignment] is [Alignment.topLeft], then the top left corner of
3899 /// each non-positioned child will be located at the same global coordinate.
3900 ///
3901 /// Partially-positioned children, those that do not specify an alignment in a
3902 /// particular axis (e.g. that have neither `top` nor `bottom` set), use the
3903 /// alignment to determine how they should be positioned in that
3904 /// under-specified axis.
3905 ///
3906 /// Defaults to [AlignmentDirectional.topStart].
3907 ///
3908 /// See also:
3909 ///
3910 /// * [Alignment], a class with convenient constants typically used to
3911 /// specify an [AlignmentGeometry].
3912 /// * [AlignmentDirectional], like [Alignment] for specifying alignments
3913 /// relative to text direction.
3914 final AlignmentGeometry alignment;
3915
3916 /// The text direction with which to resolve [alignment].
3917 ///
3918 /// Defaults to the ambient [Directionality].
3919 final TextDirection? textDirection;
3920
3921 /// How to size the non-positioned children in the stack.
3922 ///
3923 /// The constraints passed into the [Stack] from its parent are either
3924 /// loosened ([StackFit.loose]) or tightened to their biggest size
3925 /// ([StackFit.expand]).
3926 final StackFit fit;
3927
3928 /// {@macro flutter.material.Material.clipBehavior}
3929 ///
3930 /// Stacks only clip children whose _geometry_ overflows the stack. A child
3931 /// that paints outside its bounds (e.g. a box with a shadow) will not be
3932 /// clipped, regardless of the value of this property. Similarly, a child that
3933 /// itself has a descendant that overflows the stack will not be clipped, as
3934 /// only the geometry of the stack's direct children are considered.
3935 /// [Transform] is an example of a widget that can cause its children to paint
3936 /// outside its geometry.
3937 ///
3938 /// To clip children whose geometry does not overflow the stack, consider
3939 /// using a [ClipRect] widget.
3940 ///
3941 /// Defaults to [Clip.hardEdge].
3942 final Clip clipBehavior;
3943
3944 bool _debugCheckHasDirectionality(BuildContext context) {
3945 if (alignment is AlignmentDirectional && textDirection == null) {
3946 assert(debugCheckHasDirectionality(
3947 context,
3948 why: "to resolve the 'alignment' argument",
3949 hint: alignment == AlignmentDirectional.topStart ? "The default value for 'alignment' is AlignmentDirectional.topStart, which requires a text direction." : null,
3950 alternative: "Instead of providing a Directionality widget, another solution would be passing a non-directional 'alignment', or an explicit 'textDirection', to the $runtimeType.",
3951 ));
3952 }
3953 return true;
3954 }
3955
3956 @override
3957 RenderStack createRenderObject(BuildContext context) {
3958 assert(_debugCheckHasDirectionality(context));
3959 return RenderStack(
3960 alignment: alignment,
3961 textDirection: textDirection ?? Directionality.maybeOf(context),
3962 fit: fit,
3963 clipBehavior: clipBehavior,
3964 );
3965 }
3966
3967 @override
3968 void updateRenderObject(BuildContext context, RenderStack renderObject) {
3969 assert(_debugCheckHasDirectionality(context));
3970 renderObject
3971 ..alignment = alignment
3972 ..textDirection = textDirection ?? Directionality.maybeOf(context)
3973 ..fit = fit
3974 ..clipBehavior = clipBehavior;
3975 }
3976
3977 @override
3978 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
3979 super.debugFillProperties(properties);
3980 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
3981 properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
3982 properties.add(EnumProperty<StackFit>('fit', fit));
3983 properties.add(EnumProperty<Clip>('clipBehavior', clipBehavior, defaultValue: Clip.hardEdge));
3984 }
3985}
3986
3987/// A [Stack] that shows a single child from a list of children.
3988///
3989/// The displayed child is the one with the given [index]. The stack is
3990/// always as big as the largest child.
3991///
3992/// If value is null, then nothing is displayed.
3993///
3994/// {@youtube 560 315 https://www.youtube.com/watch?v=_O0PPD1Xfbk}
3995///
3996/// {@tool dartpad}
3997/// This example shows a [IndexedStack] widget being used to lay out one card
3998/// at a time from a series of cards, each keeping their respective states.
3999///
4000/// ** See code in examples/api/lib/widgets/basic/indexed_stack.0.dart **
4001/// {@end-tool}
4002///
4003/// See also:
4004///
4005/// * [Stack], for more details about stacks.
4006/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
4007class IndexedStack extends StatelessWidget {
4008 /// Creates a [Stack] widget that paints a single child.
4009 const IndexedStack({
4010 super.key,
4011 this.alignment = AlignmentDirectional.topStart,
4012 this.textDirection,
4013 this.clipBehavior = Clip.hardEdge,
4014 this.sizing = StackFit.loose,
4015 this.index = 0,
4016 this.children = const <Widget>[],
4017 });
4018
4019 /// How to align the non-positioned and partially-positioned children in the
4020 /// stack.
4021 ///
4022 /// Defaults to [AlignmentDirectional.topStart].
4023 ///
4024 /// See [Stack.alignment] for more information.
4025 final AlignmentGeometry alignment;
4026
4027 /// The text direction with which to resolve [alignment].
4028 ///
4029 /// Defaults to the ambient [Directionality].
4030 final TextDirection? textDirection;
4031
4032 /// {@macro flutter.material.Material.clipBehavior}
4033 ///
4034 /// Defaults to [Clip.hardEdge].
4035 final Clip clipBehavior;
4036
4037 /// How to size the non-positioned children in the stack.
4038 ///
4039 /// Defaults to [StackFit.loose].
4040 ///
4041 /// See [Stack.fit] for more information.
4042 final StackFit sizing;
4043
4044 /// The index of the child to show.
4045 ///
4046 /// If this is null, none of the children will be shown.
4047 final int? index;
4048
4049 /// The child widgets of the stack.
4050 ///
4051 /// Only the child at index [index] will be shown.
4052 ///
4053 /// See [Stack.children] for more information.
4054 final List<Widget> children;
4055
4056 @override
4057 Widget build(BuildContext context) {
4058 final List<Widget> wrappedChildren = List<Widget>.generate(children.length, (int i) {
4059 return Visibility.maintain(
4060 visible: i == index,
4061 child: children[i],
4062 );
4063 });
4064 return _RawIndexedStack(
4065 alignment: alignment,
4066 textDirection: textDirection,
4067 clipBehavior: clipBehavior,
4068 sizing: sizing,
4069 index: index,
4070 children: wrappedChildren,
4071 );
4072 }
4073}
4074
4075/// The render object widget that backs [IndexedStack].
4076class _RawIndexedStack extends Stack {
4077 /// Creates a [Stack] widget that paints a single child.
4078 const _RawIndexedStack({
4079 super.alignment,
4080 super.textDirection,
4081 super.clipBehavior,
4082 StackFit sizing = StackFit.loose,
4083 this.index = 0,
4084 super.children,
4085 }) : super(fit: sizing);
4086
4087 /// The index of the child to show.
4088 final int? index;
4089
4090 @override
4091 RenderIndexedStack createRenderObject(BuildContext context) {
4092 assert(_debugCheckHasDirectionality(context));
4093 return RenderIndexedStack(
4094 index: index,
4095 fit: fit,
4096 clipBehavior: clipBehavior,
4097 alignment: alignment,
4098 textDirection: textDirection ?? Directionality.maybeOf(context),
4099 );
4100 }
4101
4102 @override
4103 void updateRenderObject(BuildContext context, RenderIndexedStack renderObject) {
4104 assert(_debugCheckHasDirectionality(context));
4105 renderObject
4106 ..index = index
4107 ..fit = fit
4108 ..clipBehavior = clipBehavior
4109 ..alignment = alignment
4110 ..textDirection = textDirection ?? Directionality.maybeOf(context);
4111 }
4112
4113 @override
4114 MultiChildRenderObjectElement createElement() {
4115 return _IndexedStackElement(this);
4116 }
4117}
4118
4119class _IndexedStackElement extends MultiChildRenderObjectElement {
4120 _IndexedStackElement(_RawIndexedStack super.widget);
4121
4122 @override
4123 _RawIndexedStack get widget => super.widget as _RawIndexedStack;
4124
4125 @override
4126 void debugVisitOnstageChildren(ElementVisitor visitor) {
4127 final int? index = widget.index;
4128 // If the index is null, no child is onstage. Otherwise, only the child at
4129 // the selected index is.
4130 if (index != null && children.isNotEmpty) {
4131 visitor(children.elementAt(index));
4132 }
4133 }
4134}
4135
4136/// A widget that controls where a child of a [Stack] is positioned.
4137///
4138/// A [Positioned] widget must be a descendant of a [Stack], and the path from
4139/// the [Positioned] widget to its enclosing [Stack] must contain only
4140/// [StatelessWidget]s or [StatefulWidget]s (not other kinds of widgets, like
4141/// [RenderObjectWidget]s).
4142///
4143/// {@youtube 560 315 https://www.youtube.com/watch?v=EgtPleVwxBQ}
4144///
4145/// If a widget is wrapped in a [Positioned], then it is a _positioned_ widget
4146/// in its [Stack]. If the [top] property is non-null, the top edge of this child
4147/// will be positioned [top] layout units from the top of the stack widget. The
4148/// [right], [bottom], and [left] properties work analogously.
4149///
4150/// If both the [top] and [bottom] properties are non-null, then the child will
4151/// be forced to have exactly the height required to satisfy both constraints.
4152/// Similarly, setting the [right] and [left] properties to non-null values will
4153/// force the child to have a particular width. Alternatively the [width] and
4154/// [height] properties can be used to give the dimensions, with one
4155/// corresponding position property (e.g. [top] and [height]).
4156///
4157/// If all three values on a particular axis are null, then the
4158/// [Stack.alignment] property is used to position the child.
4159///
4160/// If all six values are null, the child is a non-positioned child. The [Stack]
4161/// uses only the non-positioned children to size itself.
4162///
4163/// See also:
4164///
4165/// * [AnimatedPositioned], which automatically transitions the child's
4166/// position over a given duration whenever the given position changes.
4167/// * [PositionedTransition], which takes a provided [Animation] to transition
4168/// changes in the child's position over a given duration.
4169/// * [PositionedDirectional], which adapts to the ambient [Directionality].
4170class Positioned extends ParentDataWidget<StackParentData> {
4171 /// Creates a widget that controls where a child of a [Stack] is positioned.
4172 ///
4173 /// Only two out of the three horizontal values ([left], [right],
4174 /// [width]), and only two out of the three vertical values ([top],
4175 /// [bottom], [height]), can be set. In each case, at least one of
4176 /// the three must be null.
4177 ///
4178 /// See also:
4179 ///
4180 /// * [Positioned.directional], which specifies the widget's horizontal
4181 /// position using `start` and `end` rather than `left` and `right`.
4182 /// * [PositionedDirectional], which is similar to [Positioned.directional]
4183 /// but adapts to the ambient [Directionality].
4184 const Positioned({
4185 super.key,
4186 this.left,
4187 this.top,
4188 this.right,
4189 this.bottom,
4190 this.width,
4191 this.height,
4192 required super.child,
4193 }) : assert(left == null || right == null || width == null),
4194 assert(top == null || bottom == null || height == null);
4195
4196 /// Creates a Positioned object with the values from the given [Rect].
4197 ///
4198 /// This sets the [left], [top], [width], and [height] properties
4199 /// from the given [Rect]. The [right] and [bottom] properties are
4200 /// set to null.
4201 Positioned.fromRect({
4202 super.key,
4203 required Rect rect,
4204 required super.child,
4205 }) : left = rect.left,
4206 top = rect.top,
4207 width = rect.width,
4208 height = rect.height,
4209 right = null,
4210 bottom = null;
4211
4212 /// Creates a Positioned object with the values from the given [RelativeRect].
4213 ///
4214 /// This sets the [left], [top], [right], and [bottom] properties from the
4215 /// given [RelativeRect]. The [height] and [width] properties are set to null.
4216 Positioned.fromRelativeRect({
4217 super.key,
4218 required RelativeRect rect,
4219 required super.child,
4220 }) : left = rect.left,
4221 top = rect.top,
4222 right = rect.right,
4223 bottom = rect.bottom,
4224 width = null,
4225 height = null;
4226
4227 /// Creates a Positioned object with [left], [top], [right], and [bottom] set
4228 /// to 0.0 unless a value for them is passed.
4229 const Positioned.fill({
4230 super.key,
4231 this.left = 0.0,
4232 this.top = 0.0,
4233 this.right = 0.0,
4234 this.bottom = 0.0,
4235 required super.child,
4236 }) : width = null,
4237 height = null;
4238
4239 /// Creates a widget that controls where a child of a [Stack] is positioned.
4240 ///
4241 /// Only two out of the three horizontal values (`start`, `end`,
4242 /// [width]), and only two out of the three vertical values ([top],
4243 /// [bottom], [height]), can be set. In each case, at least one of
4244 /// the three must be null.
4245 ///
4246 /// If `textDirection` is [TextDirection.rtl], then the `start` argument is
4247 /// used for the [right] property and the `end` argument is used for the
4248 /// [left] property. Otherwise, if `textDirection` is [TextDirection.ltr],
4249 /// then the `start` argument is used for the [left] property and the `end`
4250 /// argument is used for the [right] property.
4251 ///
4252 /// See also:
4253 ///
4254 /// * [PositionedDirectional], which adapts to the ambient [Directionality].
4255 factory Positioned.directional({
4256 Key? key,
4257 required TextDirection textDirection,
4258 double? start,
4259 double? top,
4260 double? end,
4261 double? bottom,
4262 double? width,
4263 double? height,
4264 required Widget child,
4265 }) {
4266 double? left;
4267 double? right;
4268 switch (textDirection) {
4269 case TextDirection.rtl:
4270 left = end;
4271 right = start;
4272 case TextDirection.ltr:
4273 left = start;
4274 right = end;
4275 }
4276 return Positioned(
4277 key: key,
4278 left: left,
4279 top: top,
4280 right: right,
4281 bottom: bottom,
4282 width: width,
4283 height: height,
4284 child: child,
4285 );
4286 }
4287
4288 /// The distance that the child's left edge is inset from the left of the stack.
4289 ///
4290 /// Only two out of the three horizontal values ([left], [right], [width]) can be
4291 /// set. The third must be null.
4292 ///
4293 /// If all three are null, the [Stack.alignment] is used to position the child
4294 /// horizontally.
4295 final double? left;
4296
4297 /// The distance that the child's top edge is inset from the top of the stack.
4298 ///
4299 /// Only two out of the three vertical values ([top], [bottom], [height]) can be
4300 /// set. The third must be null.
4301 ///
4302 /// If all three are null, the [Stack.alignment] is used to position the child
4303 /// vertically.
4304 final double? top;
4305
4306 /// The distance that the child's right edge is inset from the right of the stack.
4307 ///
4308 /// Only two out of the three horizontal values ([left], [right], [width]) can be
4309 /// set. The third must be null.
4310 ///
4311 /// If all three are null, the [Stack.alignment] is used to position the child
4312 /// horizontally.
4313 final double? right;
4314
4315 /// The distance that the child's bottom edge is inset from the bottom of the stack.
4316 ///
4317 /// Only two out of the three vertical values ([top], [bottom], [height]) can be
4318 /// set. The third must be null.
4319 ///
4320 /// If all three are null, the [Stack.alignment] is used to position the child
4321 /// vertically.
4322 final double? bottom;
4323
4324 /// The child's width.
4325 ///
4326 /// Only two out of the three horizontal values ([left], [right], [width]) can be
4327 /// set. The third must be null.
4328 ///
4329 /// If all three are null, the [Stack.alignment] is used to position the child
4330 /// horizontally.
4331 final double? width;
4332
4333 /// The child's height.
4334 ///
4335 /// Only two out of the three vertical values ([top], [bottom], [height]) can be
4336 /// set. The third must be null.
4337 ///
4338 /// If all three are null, the [Stack.alignment] is used to position the child
4339 /// vertically.
4340 final double? height;
4341
4342 @override
4343 void applyParentData(RenderObject renderObject) {
4344 assert(renderObject.parentData is StackParentData);
4345 final StackParentData parentData = renderObject.parentData! as StackParentData;
4346 bool needsLayout = false;
4347
4348 if (parentData.left != left) {
4349 parentData.left = left;
4350 needsLayout = true;
4351 }
4352
4353 if (parentData.top != top) {
4354 parentData.top = top;
4355 needsLayout = true;
4356 }
4357
4358 if (parentData.right != right) {
4359 parentData.right = right;
4360 needsLayout = true;
4361 }
4362
4363 if (parentData.bottom != bottom) {
4364 parentData.bottom = bottom;
4365 needsLayout = true;
4366 }
4367
4368 if (parentData.width != width) {
4369 parentData.width = width;
4370 needsLayout = true;
4371 }
4372
4373 if (parentData.height != height) {
4374 parentData.height = height;
4375 needsLayout = true;
4376 }
4377
4378 if (needsLayout) {
4379 final RenderObject? targetParent = renderObject.parent;
4380 if (targetParent is RenderObject) {
4381 targetParent.markNeedsLayout();
4382 }
4383 }
4384 }
4385
4386 @override
4387 Type get debugTypicalAncestorWidgetClass => Stack;
4388
4389 @override
4390 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
4391 super.debugFillProperties(properties);
4392 properties.add(DoubleProperty('left', left, defaultValue: null));
4393 properties.add(DoubleProperty('top', top, defaultValue: null));
4394 properties.add(DoubleProperty('right', right, defaultValue: null));
4395 properties.add(DoubleProperty('bottom', bottom, defaultValue: null));
4396 properties.add(DoubleProperty('width', width, defaultValue: null));
4397 properties.add(DoubleProperty('height', height, defaultValue: null));
4398 }
4399}
4400
4401/// A widget that controls where a child of a [Stack] is positioned without
4402/// committing to a specific [TextDirection].
4403///
4404/// The ambient [Directionality] is used to determine whether [start] is to the
4405/// left or to the right.
4406///
4407/// A [PositionedDirectional] widget must be a descendant of a [Stack], and the
4408/// path from the [PositionedDirectional] widget to its enclosing [Stack] must
4409/// contain only [StatelessWidget]s or [StatefulWidget]s (not other kinds of
4410/// widgets, like [RenderObjectWidget]s).
4411///
4412/// If a widget is wrapped in a [PositionedDirectional], then it is a
4413/// _positioned_ widget in its [Stack]. If the [top] property is non-null, the
4414/// top edge of this child/ will be positioned [top] layout units from the top
4415/// of the stack widget. The [start], [bottom], and [end] properties work
4416/// analogously.
4417///
4418/// If both the [top] and [bottom] properties are non-null, then the child will
4419/// be forced to have exactly the height required to satisfy both constraints.
4420/// Similarly, setting the [start] and [end] properties to non-null values will
4421/// force the child to have a particular width. Alternatively the [width] and
4422/// [height] properties can be used to give the dimensions, with one
4423/// corresponding position property (e.g. [top] and [height]).
4424///
4425/// See also:
4426///
4427/// * [Positioned], which specifies the widget's position visually.
4428/// * [Positioned.directional], which also specifies the widget's horizontal
4429/// position using [start] and [end] but has an explicit [TextDirection].
4430/// * [AnimatedPositionedDirectional], which automatically transitions
4431/// the child's position over a given duration whenever the given position
4432/// changes.
4433class PositionedDirectional extends StatelessWidget {
4434 /// Creates a widget that controls where a child of a [Stack] is positioned.
4435 ///
4436 /// Only two out of the three horizontal values (`start`, `end`,
4437 /// [width]), and only two out of the three vertical values ([top],
4438 /// [bottom], [height]), can be set. In each case, at least one of
4439 /// the three must be null.
4440 ///
4441 /// See also:
4442 ///
4443 /// * [Positioned.directional], which also specifies the widget's horizontal
4444 /// position using [start] and [end] but has an explicit [TextDirection].
4445 const PositionedDirectional({
4446 super.key,
4447 this.start,
4448 this.top,
4449 this.end,
4450 this.bottom,
4451 this.width,
4452 this.height,
4453 required this.child,
4454 });
4455
4456 /// The distance that the child's leading edge is inset from the leading edge
4457 /// of the stack.
4458 ///
4459 /// Only two out of the three horizontal values ([start], [end], [width]) can be
4460 /// set. The third must be null.
4461 final double? start;
4462
4463 /// The distance that the child's top edge is inset from the top of the stack.
4464 ///
4465 /// Only two out of the three vertical values ([top], [bottom], [height]) can be
4466 /// set. The third must be null.
4467 final double? top;
4468
4469 /// The distance that the child's trailing edge is inset from the trailing
4470 /// edge of the stack.
4471 ///
4472 /// Only two out of the three horizontal values ([start], [end], [width]) can be
4473 /// set. The third must be null.
4474 final double? end;
4475
4476 /// The distance that the child's bottom edge is inset from the bottom of the stack.
4477 ///
4478 /// Only two out of the three vertical values ([top], [bottom], [height]) can be
4479 /// set. The third must be null.
4480 final double? bottom;
4481
4482 /// The child's width.
4483 ///
4484 /// Only two out of the three horizontal values ([start], [end], [width]) can be
4485 /// set. The third must be null.
4486 final double? width;
4487
4488 /// The child's height.
4489 ///
4490 /// Only two out of the three vertical values ([top], [bottom], [height]) can be
4491 /// set. The third must be null.
4492 final double? height;
4493
4494 /// The widget below this widget in the tree.
4495 ///
4496 /// {@macro flutter.widgets.ProxyWidget.child}
4497 final Widget child;
4498
4499 @override
4500 Widget build(BuildContext context) {
4501 return Positioned.directional(
4502 textDirection: Directionality.of(context),
4503 start: start,
4504 top: top,
4505 end: end,
4506 bottom: bottom,
4507 width: width,
4508 height: height,
4509 child: child,
4510 );
4511 }
4512}
4513
4514/// A widget that displays its children in a one-dimensional array.
4515///
4516/// The [Flex] widget allows you to control the axis along which the children are
4517/// placed (horizontal or vertical). This is referred to as the _main axis_. If
4518/// you know the main axis in advance, then consider using a [Row] (if it's
4519/// horizontal) or [Column] (if it's vertical) instead, because that will be less
4520/// verbose.
4521///
4522/// To cause a child to expand to fill the available space in the [direction]
4523/// of this widget's main axis, wrap the child in an [Expanded] widget.
4524///
4525/// The [Flex] widget does not scroll (and in general it is considered an error
4526/// to have more children in a [Flex] than will fit in the available room). If
4527/// you have some widgets and want them to be able to scroll if there is
4528/// insufficient room, consider using a [ListView].
4529///
4530/// The [Flex] widget does not allow its children to wrap across multiple
4531/// horizontal or vertical runs. For a widget that allows its children to wrap,
4532/// consider using the [Wrap] widget instead of [Flex].
4533///
4534/// If you only have one child, then rather than using [Flex], [Row], or
4535/// [Column], consider using [Align] or [Center] to position the child.
4536///
4537/// ## Layout algorithm
4538///
4539/// _This section describes how a [Flex] is rendered by the framework._
4540/// _See [BoxConstraints] for an introduction to box layout models._
4541///
4542/// Layout for a [Flex] proceeds in six steps:
4543///
4544/// 1. Layout each child with a null or zero flex factor (e.g., those that are
4545/// not [Expanded]) with unbounded main axis constraints and the incoming
4546/// cross axis constraints. If the [crossAxisAlignment] is
4547/// [CrossAxisAlignment.stretch], instead use tight cross axis constraints
4548/// that match the incoming max extent in the cross axis.
4549/// 2. Divide the remaining main axis space among the children with non-zero
4550/// flex factors (e.g., those that are [Expanded]) according to their flex
4551/// factor. For example, a child with a flex factor of 2.0 will receive twice
4552/// the amount of main axis space as a child with a flex factor of 1.0.
4553/// 3. Layout each of the remaining children with the same cross axis
4554/// constraints as in step 1, but instead of using unbounded main axis
4555/// constraints, use max axis constraints based on the amount of space
4556/// allocated in step 2. Children with [Flexible.fit] properties that are
4557/// [FlexFit.tight] are given tight constraints (i.e., forced to fill the
4558/// allocated space), and children with [Flexible.fit] properties that are
4559/// [FlexFit.loose] are given loose constraints (i.e., not forced to fill the
4560/// allocated space).
4561/// 4. The cross axis extent of the [Flex] is the maximum cross axis extent of
4562/// the children (which will always satisfy the incoming constraints).
4563/// 5. The main axis extent of the [Flex] is determined by the [mainAxisSize]
4564/// property. If the [mainAxisSize] property is [MainAxisSize.max], then the
4565/// main axis extent of the [Flex] is the max extent of the incoming main
4566/// axis constraints. If the [mainAxisSize] property is [MainAxisSize.min],
4567/// then the main axis extent of the [Flex] is the sum of the main axis
4568/// extents of the children (subject to the incoming constraints).
4569/// 6. Determine the position for each child according to the
4570/// [mainAxisAlignment] and the [crossAxisAlignment]. For example, if the
4571/// [mainAxisAlignment] is [MainAxisAlignment.spaceBetween], any main axis
4572/// space that has not been allocated to children is divided evenly and
4573/// placed between the children.
4574///
4575/// See also:
4576///
4577/// * [Row], for a version of this widget that is always horizontal.
4578/// * [Column], for a version of this widget that is always vertical.
4579/// * [Expanded], to indicate children that should take all the remaining room.
4580/// * [Flexible], to indicate children that should share the remaining room.
4581/// * [Spacer], a widget that takes up space proportional to its flex value.
4582/// that may be sized smaller (leaving some remaining room unused).
4583/// * [Wrap], for a widget that allows its children to wrap over multiple _runs_.
4584/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
4585class Flex extends MultiChildRenderObjectWidget {
4586 /// Creates a flex layout.
4587 ///
4588 /// The [direction] is required.
4589 ///
4590 /// If [crossAxisAlignment] is [CrossAxisAlignment.baseline], then
4591 /// [textBaseline] must not be null.
4592 ///
4593 /// The [textDirection] argument defaults to the ambient [Directionality], if
4594 /// any. If there is no ambient directionality, and a text direction is going
4595 /// to be necessary to decide which direction to lay the children in or to
4596 /// disambiguate `start` or `end` values for the main or cross axis
4597 /// directions, the [textDirection] must not be null.
4598 const Flex({
4599 super.key,
4600 required this.direction,
4601 this.mainAxisAlignment = MainAxisAlignment.start,
4602 this.mainAxisSize = MainAxisSize.max,
4603 this.crossAxisAlignment = CrossAxisAlignment.center,
4604 this.textDirection,
4605 this.verticalDirection = VerticalDirection.down,
4606 this.textBaseline, // NO DEFAULT: we don't know what the text's baseline should be
4607 this.clipBehavior = Clip.none,
4608 super.children,
4609 }) : assert(!identical(crossAxisAlignment, CrossAxisAlignment.baseline) || textBaseline != null, 'textBaseline is required if you specify the crossAxisAlignment with CrossAxisAlignment.baseline');
4610 // Cannot use == in the assert above instead of identical because of https://github.com/dart-lang/language/issues/1811.
4611
4612 /// The direction to use as the main axis.
4613 ///
4614 /// If you know the axis in advance, then consider using a [Row] (if it's
4615 /// horizontal) or [Column] (if it's vertical) instead of a [Flex], since that
4616 /// will be less verbose. (For [Row] and [Column] this property is fixed to
4617 /// the appropriate axis.)
4618 final Axis direction;
4619
4620 /// How the children should be placed along the main axis.
4621 ///
4622 /// For example, [MainAxisAlignment.start], the default, places the children
4623 /// at the start (i.e., the left for a [Row] or the top for a [Column]) of the
4624 /// main axis.
4625 final MainAxisAlignment mainAxisAlignment;
4626
4627 /// How much space should be occupied in the main axis.
4628 ///
4629 /// After allocating space to children, there might be some remaining free
4630 /// space. This value controls whether to maximize or minimize the amount of
4631 /// free space, subject to the incoming layout constraints.
4632 ///
4633 /// If some children have a non-zero flex factors (and none have a fit of
4634 /// [FlexFit.loose]), they will expand to consume all the available space and
4635 /// there will be no remaining free space to maximize or minimize, making this
4636 /// value irrelevant to the final layout.
4637 final MainAxisSize mainAxisSize;
4638
4639 /// How the children should be placed along the cross axis.
4640 ///
4641 /// For example, [CrossAxisAlignment.center], the default, centers the
4642 /// children in the cross axis (e.g., horizontally for a [Column]).
4643 final CrossAxisAlignment crossAxisAlignment;
4644
4645 /// Determines the order to lay children out horizontally and how to interpret
4646 /// `start` and `end` in the horizontal direction.
4647 ///
4648 /// Defaults to the ambient [Directionality].
4649 ///
4650 /// If [textDirection] is [TextDirection.rtl], then the direction in which
4651 /// text flows starts from right to left. Otherwise, if [textDirection] is
4652 /// [TextDirection.ltr], then the direction in which text flows starts from
4653 /// left to right.
4654 ///
4655 /// If the [direction] is [Axis.horizontal], this controls the order in which
4656 /// the children are positioned (left-to-right or right-to-left), and the
4657 /// meaning of the [mainAxisAlignment] property's [MainAxisAlignment.start] and
4658 /// [MainAxisAlignment.end] values.
4659 ///
4660 /// If the [direction] is [Axis.horizontal], and either the
4661 /// [mainAxisAlignment] is either [MainAxisAlignment.start] or
4662 /// [MainAxisAlignment.end], or there's more than one child, then the
4663 /// [textDirection] (or the ambient [Directionality]) must not be null.
4664 ///
4665 /// If the [direction] is [Axis.vertical], this controls the meaning of the
4666 /// [crossAxisAlignment] property's [CrossAxisAlignment.start] and
4667 /// [CrossAxisAlignment.end] values.
4668 ///
4669 /// If the [direction] is [Axis.vertical], and the [crossAxisAlignment] is
4670 /// either [CrossAxisAlignment.start] or [CrossAxisAlignment.end], then the
4671 /// [textDirection] (or the ambient [Directionality]) must not be null.
4672 final TextDirection? textDirection;
4673
4674 /// Determines the order to lay children out vertically and how to interpret
4675 /// `start` and `end` in the vertical direction.
4676 ///
4677 /// Defaults to [VerticalDirection.down].
4678 ///
4679 /// If the [direction] is [Axis.vertical], this controls which order children
4680 /// are painted in (down or up), the meaning of the [mainAxisAlignment]
4681 /// property's [MainAxisAlignment.start] and [MainAxisAlignment.end] values.
4682 ///
4683 /// If the [direction] is [Axis.vertical], and either the [mainAxisAlignment]
4684 /// is either [MainAxisAlignment.start] or [MainAxisAlignment.end], or there's
4685 /// more than one child, then the [verticalDirection] must not be null.
4686 ///
4687 /// If the [direction] is [Axis.horizontal], this controls the meaning of the
4688 /// [crossAxisAlignment] property's [CrossAxisAlignment.start] and
4689 /// [CrossAxisAlignment.end] values.
4690 ///
4691 /// If the [direction] is [Axis.horizontal], and the [crossAxisAlignment] is
4692 /// either [CrossAxisAlignment.start] or [CrossAxisAlignment.end], then the
4693 /// [verticalDirection] must not be null.
4694 final VerticalDirection verticalDirection;
4695
4696 /// If aligning items according to their baseline, which baseline to use.
4697 ///
4698 /// This must be set if using baseline alignment. There is no default because there is no
4699 /// way for the framework to know the correct baseline _a priori_.
4700 final TextBaseline? textBaseline;
4701
4702 /// {@macro flutter.material.Material.clipBehavior}
4703 ///
4704 /// Defaults to [Clip.none].
4705 final Clip clipBehavior;
4706
4707 bool get _needTextDirection {
4708 switch (direction) {
4709 case Axis.horizontal:
4710 return true; // because it affects the layout order.
4711 case Axis.vertical:
4712 return crossAxisAlignment == CrossAxisAlignment.start
4713 || crossAxisAlignment == CrossAxisAlignment.end;
4714 }
4715 }
4716
4717 /// The value to pass to [RenderFlex.textDirection].
4718 ///
4719 /// This value is derived from the [textDirection] property and the ambient
4720 /// [Directionality]. The value is null if there is no need to specify the
4721 /// text direction. In practice there's always a need to specify the direction
4722 /// except for vertical flexes (e.g. [Column]s) whose [crossAxisAlignment] is
4723 /// not dependent on the text direction (not `start` or `end`). In particular,
4724 /// a [Row] always needs a text direction because the text direction controls
4725 /// its layout order. (For [Column]s, the layout order is controlled by
4726 /// [verticalDirection], which is always specified as it does not depend on an
4727 /// inherited widget and defaults to [VerticalDirection.down].)
4728 ///
4729 /// This method exists so that subclasses of [Flex] that create their own
4730 /// render objects that are derived from [RenderFlex] can do so and still use
4731 /// the logic for providing a text direction only when it is necessary.
4732 @protected
4733 TextDirection? getEffectiveTextDirection(BuildContext context) {
4734 return textDirection ?? (_needTextDirection ? Directionality.maybeOf(context) : null);
4735 }
4736
4737 @override
4738 RenderFlex createRenderObject(BuildContext context) {
4739 return RenderFlex(
4740 direction: direction,
4741 mainAxisAlignment: mainAxisAlignment,
4742 mainAxisSize: mainAxisSize,
4743 crossAxisAlignment: crossAxisAlignment,
4744 textDirection: getEffectiveTextDirection(context),
4745 verticalDirection: verticalDirection,
4746 textBaseline: textBaseline,
4747 clipBehavior: clipBehavior,
4748 );
4749 }
4750
4751 @override
4752 void updateRenderObject(BuildContext context, covariant RenderFlex renderObject) {
4753 renderObject
4754 ..direction = direction
4755 ..mainAxisAlignment = mainAxisAlignment
4756 ..mainAxisSize = mainAxisSize
4757 ..crossAxisAlignment = crossAxisAlignment
4758 ..textDirection = getEffectiveTextDirection(context)
4759 ..verticalDirection = verticalDirection
4760 ..textBaseline = textBaseline
4761 ..clipBehavior = clipBehavior;
4762 }
4763
4764 @override
4765 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
4766 super.debugFillProperties(properties);
4767 properties.add(EnumProperty<Axis>('direction', direction));
4768 properties.add(EnumProperty<MainAxisAlignment>('mainAxisAlignment', mainAxisAlignment));
4769 properties.add(EnumProperty<MainAxisSize>('mainAxisSize', mainAxisSize, defaultValue: MainAxisSize.max));
4770 properties.add(EnumProperty<CrossAxisAlignment>('crossAxisAlignment', crossAxisAlignment));
4771 properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
4772 properties.add(EnumProperty<VerticalDirection>('verticalDirection', verticalDirection, defaultValue: VerticalDirection.down));
4773 properties.add(EnumProperty<TextBaseline>('textBaseline', textBaseline, defaultValue: null));
4774 }
4775}
4776
4777/// A widget that displays its children in a horizontal array.
4778///
4779/// To cause a child to expand to fill the available horizontal space, wrap the
4780/// child in an [Expanded] widget.
4781///
4782/// The [Row] widget does not scroll (and in general it is considered an error
4783/// to have more children in a [Row] than will fit in the available room). If
4784/// you have a line of widgets and want them to be able to scroll if there is
4785/// insufficient room, consider using a [ListView].
4786///
4787/// For a vertical variant, see [Column].
4788///
4789/// If you only have one child, then consider using [Align] or [Center] to
4790/// position the child.
4791///
4792/// {@tool snippet}
4793///
4794/// This example divides the available space into three (horizontally), and
4795/// places text centered in the first two cells and the Flutter logo centered in
4796/// the third:
4797///
4798/// ![](https://flutter.github.io/assets-for-api-docs/assets/widgets/row.png)
4799///
4800/// ```dart
4801/// const Row(
4802/// children: <Widget>[
4803/// Expanded(
4804/// child: Text('Deliver features faster', textAlign: TextAlign.center),
4805/// ),
4806/// Expanded(
4807/// child: Text('Craft beautiful UIs', textAlign: TextAlign.center),
4808/// ),
4809/// Expanded(
4810/// child: FittedBox(
4811/// child: FlutterLogo(),
4812/// ),
4813/// ),
4814/// ],
4815/// )
4816/// ```
4817/// {@end-tool}
4818///
4819/// ## Troubleshooting
4820///
4821/// ### Why does my row have a yellow and black warning stripe?
4822///
4823/// If the non-flexible contents of the row (those that are not wrapped in
4824/// [Expanded] or [Flexible] widgets) are together wider than the row itself,
4825/// then the row is said to have overflowed. When a row overflows, the row does
4826/// not have any remaining space to share between its [Expanded] and [Flexible]
4827/// children. The row reports this by drawing a yellow and black striped
4828/// warning box on the edge that is overflowing. If there is room on the outside
4829/// of the row, the amount of overflow is printed in red lettering.
4830///
4831/// #### Story time
4832///
4833/// Suppose, for instance, that you had this code:
4834///
4835/// ```dart
4836/// const Row(
4837/// children: <Widget>[
4838/// FlutterLogo(),
4839/// Text("Flutter's hot reload helps you quickly and easily experiment, build UIs, add features, and fix bug faster. Experience sub-second reload times, without losing state, on emulators, simulators, and hardware for iOS and Android."),
4840/// Icon(Icons.sentiment_very_satisfied),
4841/// ],
4842/// )
4843/// ```
4844///
4845/// The row first asks its first child, the [FlutterLogo], to lay out, at
4846/// whatever size the logo would like. The logo is friendly and happily decides
4847/// to be 24 pixels to a side. This leaves lots of room for the next child. The
4848/// row then asks that next child, the text, to lay out, at whatever size it
4849/// thinks is best.
4850///
4851/// At this point, the text, not knowing how wide is too wide, says "Ok, I will
4852/// be thiiiiiiiiiiiiiiiiiiiis wide.", and goes well beyond the space that the
4853/// row has available, not wrapping. The row responds, "That's not fair, now I
4854/// have no more room available for my other children!", and gets angry and
4855/// sprouts a yellow and black strip.
4856///
4857/// ![](https://flutter.github.io/assets-for-api-docs/assets/widgets/row_error.png)
4858///
4859/// The fix is to wrap the second child in an [Expanded] widget, which tells the
4860/// row that the child should be given the remaining room:
4861///
4862/// ```dart
4863/// const Row(
4864/// children: <Widget>[
4865/// FlutterLogo(),
4866/// Expanded(
4867/// child: Text("Flutter's hot reload helps you quickly and easily experiment, build UIs, add features, and fix bug faster. Experience sub-second reload times, without losing state, on emulators, simulators, and hardware for iOS and Android."),
4868/// ),
4869/// Icon(Icons.sentiment_very_satisfied),
4870/// ],
4871/// )
4872/// ```
4873///
4874/// Now, the row first asks the logo to lay out, and then asks the _icon_ to lay
4875/// out. The [Icon], like the logo, is happy to take on a reasonable size (also
4876/// 24 pixels, not coincidentally, since both [FlutterLogo] and [Icon] honor the
4877/// ambient [IconTheme]). This leaves some room left over, and now the row tells
4878/// the text exactly how wide to be: the exact width of the remaining space. The
4879/// text, now happy to comply to a reasonable request, wraps the text within
4880/// that width, and you end up with a paragraph split over several lines.
4881///
4882/// ![](https://flutter.github.io/assets-for-api-docs/assets/widgets/row_fixed.png)
4883///
4884/// The [textDirection] property controls the direction that children are rendered in.
4885/// [TextDirection.ltr] is the default [textDirection] of [Row] children, so the first
4886/// child is rendered at the `start` of the [Row], to the left, with subsequent children
4887/// following to the right. If you want to order children in the opposite
4888/// direction (right to left), then [textDirection] can be set to
4889/// [TextDirection.rtl]. This is shown in the example below
4890///
4891/// ```dart
4892/// const Row(
4893/// textDirection: TextDirection.rtl,
4894/// children: <Widget>[
4895/// FlutterLogo(),
4896/// Expanded(
4897/// child: Text("Flutter's hot reload helps you quickly and easily experiment, build UIs, add features, and fix bug faster. Experience sub-second reload times, without losing state, on emulators, simulators, and hardware for iOS and Android."),
4898/// ),
4899/// Icon(Icons.sentiment_very_satisfied),
4900/// ],
4901/// )
4902/// ```
4903///
4904/// ![](https://flutter.github.io/assets-for-api-docs/assets/widgets/row_textDirection.png)
4905///
4906/// ## Layout algorithm
4907///
4908/// _This section describes how a [Row] is rendered by the framework._
4909/// _See [BoxConstraints] for an introduction to box layout models._
4910///
4911/// Layout for a [Row] proceeds in six steps:
4912///
4913/// 1. Layout each child with a null or zero flex factor (e.g., those that are
4914/// not [Expanded]) with unbounded horizontal constraints and the incoming
4915/// vertical constraints. If the [crossAxisAlignment] is
4916/// [CrossAxisAlignment.stretch], instead use tight vertical constraints that
4917/// match the incoming max height.
4918/// 2. Divide the remaining horizontal space among the children with non-zero
4919/// flex factors (e.g., those that are [Expanded]) according to their flex
4920/// factor. For example, a child with a flex factor of 2.0 will receive twice
4921/// the amount of horizontal space as a child with a flex factor of 1.0.
4922/// 3. Layout each of the remaining children with the same vertical constraints
4923/// as in step 1, but instead of using unbounded horizontal constraints, use
4924/// horizontal constraints based on the amount of space allocated in step 2.
4925/// Children with [Flexible.fit] properties that are [FlexFit.tight] are
4926/// given tight constraints (i.e., forced to fill the allocated space), and
4927/// children with [Flexible.fit] properties that are [FlexFit.loose] are
4928/// given loose constraints (i.e., not forced to fill the allocated space).
4929/// 4. The height of the [Row] is the maximum height of the children (which will
4930/// always satisfy the incoming vertical constraints).
4931/// 5. The width of the [Row] is determined by the [mainAxisSize] property. If
4932/// the [mainAxisSize] property is [MainAxisSize.max], then the width of the
4933/// [Row] is the max width of the incoming constraints. If the [mainAxisSize]
4934/// property is [MainAxisSize.min], then the width of the [Row] is the sum
4935/// of widths of the children (subject to the incoming constraints).
4936/// 6. Determine the position for each child according to the
4937/// [mainAxisAlignment] and the [crossAxisAlignment]. For example, if the
4938/// [mainAxisAlignment] is [MainAxisAlignment.spaceBetween], any horizontal
4939/// space that has not been allocated to children is divided evenly and
4940/// placed between the children.
4941///
4942/// See also:
4943///
4944/// * [Column], for a vertical equivalent.
4945/// * [Flex], if you don't know in advance if you want a horizontal or vertical
4946/// arrangement.
4947/// * [Expanded], to indicate children that should take all the remaining room.
4948/// * [Flexible], to indicate children that should share the remaining room but
4949/// that may by sized smaller (leaving some remaining room unused).
4950/// * [Spacer], a widget that takes up space proportional to its flex value.
4951/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
4952class Row extends Flex {
4953 /// Creates a horizontal array of children.
4954 ///
4955 /// If [crossAxisAlignment] is [CrossAxisAlignment.baseline], then
4956 /// [textBaseline] must not be null.
4957 ///
4958 /// The [textDirection] argument defaults to the ambient [Directionality], if
4959 /// any. If there is no ambient directionality, and a text direction is going
4960 /// to be necessary to determine the layout order (which is always the case
4961 /// unless the row has no children or only one child) or to disambiguate
4962 /// `start` or `end` values for the [mainAxisAlignment], the [textDirection]
4963 /// must not be null.
4964 const Row({
4965 super.key,
4966 super.mainAxisAlignment,
4967 super.mainAxisSize,
4968 super.crossAxisAlignment,
4969 super.textDirection,
4970 super.verticalDirection,
4971 super.textBaseline, // NO DEFAULT: we don't know what the text's baseline should be
4972 super.children,
4973 }) : super(
4974 direction: Axis.horizontal,
4975 );
4976}
4977
4978/// A widget that displays its children in a vertical array.
4979///
4980/// To cause a child to expand to fill the available vertical space, wrap the
4981/// child in an [Expanded] widget.
4982///
4983/// The [Column] widget does not scroll (and in general it is considered an error
4984/// to have more children in a [Column] than will fit in the available room). If
4985/// you have a line of widgets and want them to be able to scroll if there is
4986/// insufficient room, consider using a [ListView].
4987///
4988/// For a horizontal variant, see [Row].
4989///
4990/// If you only have one child, then consider using [Align] or [Center] to
4991/// position the child.
4992///
4993/// {@tool snippet}
4994///
4995/// This example uses a [Column] to arrange three widgets vertically, the last
4996/// being made to fill all the remaining space.
4997///
4998/// ![Using the Column in this way creates two short lines of text with a large Flutter underneath.](https://flutter.github.io/assets-for-api-docs/assets/widgets/column.png)
4999///
5000/// ```dart
5001/// const Column(
5002/// children: <Widget>[
5003/// Text('Deliver features faster'),
5004/// Text('Craft beautiful UIs'),
5005/// Expanded(
5006/// child: FittedBox(
5007/// child: FlutterLogo(),
5008/// ),
5009/// ),
5010/// ],
5011/// )
5012/// ```
5013/// {@end-tool}
5014/// {@tool snippet}
5015///
5016/// In the sample above, the text and the logo are centered on each line. In the
5017/// following example, the [crossAxisAlignment] is set to
5018/// [CrossAxisAlignment.start], so that the children are left-aligned. The
5019/// [mainAxisSize] is set to [MainAxisSize.min], so that the column shrinks to
5020/// fit the children.
5021///
5022/// ![](https://flutter.github.io/assets-for-api-docs/assets/widgets/column_properties.png)
5023///
5024/// ```dart
5025/// Column(
5026/// crossAxisAlignment: CrossAxisAlignment.start,
5027/// mainAxisSize: MainAxisSize.min,
5028/// children: <Widget>[
5029/// const Text('We move under cover and we move as one'),
5030/// const Text('Through the night, we have one shot to live another day'),
5031/// const Text('We cannot let a stray gunshot give us away'),
5032/// const Text('We will fight up close, seize the moment and stay in it'),
5033/// const Text('It’s either that or meet the business end of a bayonet'),
5034/// const Text('The code word is ‘Rochambeau,’ dig me?'),
5035/// Text('Rochambeau!', style: DefaultTextStyle.of(context).style.apply(fontSizeFactor: 2.0)),
5036/// ],
5037/// )
5038/// ```
5039/// {@end-tool}
5040///
5041/// ## Troubleshooting
5042///
5043/// ### When the incoming vertical constraints are unbounded
5044///
5045/// When a [Column] has one or more [Expanded] or [Flexible] children, and is
5046/// placed in another [Column], or in a [ListView], or in some other context
5047/// that does not provide a maximum height constraint for the [Column], you will
5048/// get an exception at runtime saying that there are children with non-zero
5049/// flex but the vertical constraints are unbounded.
5050///
5051/// The problem, as described in the details that accompany that exception, is
5052/// that using [Flexible] or [Expanded] means that the remaining space after
5053/// laying out all the other children must be shared equally, but if the
5054/// incoming vertical constraints are unbounded, there is infinite remaining
5055/// space.
5056///
5057/// The key to solving this problem is usually to determine why the [Column] is
5058/// receiving unbounded vertical constraints.
5059///
5060/// One common reason for this to happen is that the [Column] has been placed in
5061/// another [Column] (without using [Expanded] or [Flexible] around the inner
5062/// nested [Column]). When a [Column] lays out its non-flex children (those that
5063/// have neither [Expanded] or [Flexible] around them), it gives them unbounded
5064/// constraints so that they can determine their own dimensions (passing
5065/// unbounded constraints usually signals to the child that it should
5066/// shrink-wrap its contents). The solution in this case is typically to just
5067/// wrap the inner column in an [Expanded] to indicate that it should take the
5068/// remaining space of the outer column, rather than being allowed to take any
5069/// amount of room it desires.
5070///
5071/// Another reason for this message to be displayed is nesting a [Column] inside
5072/// a [ListView] or other vertical scrollable. In that scenario, there really is
5073/// infinite vertical space (the whole point of a vertical scrolling list is to
5074/// allow infinite space vertically). In such scenarios, it is usually worth
5075/// examining why the inner [Column] should have an [Expanded] or [Flexible]
5076/// child: what size should the inner children really be? The solution in this
5077/// case is typically to remove the [Expanded] or [Flexible] widgets from around
5078/// the inner children.
5079///
5080/// {@youtube 560 315 https://www.youtube.com/watch?v=jckqXR5CrPI}
5081///
5082/// For more discussion about constraints, see [BoxConstraints].
5083///
5084/// ### The yellow and black striped banner
5085///
5086/// When the contents of a [Column] exceed the amount of space available, the
5087/// [Column] overflows, and the contents are clipped. In debug mode, a yellow
5088/// and black striped bar is rendered at the overflowing edge to indicate the
5089/// problem, and a message is printed below the [Column] saying how much
5090/// overflow was detected.
5091///
5092/// The usual solution is to use a [ListView] rather than a [Column], to enable
5093/// the contents to scroll when vertical space is limited.
5094///
5095/// ## Layout algorithm
5096///
5097/// _This section describes how a [Column] is rendered by the framework._
5098/// _See [BoxConstraints] for an introduction to box layout models._
5099///
5100/// Layout for a [Column] proceeds in six steps:
5101///
5102/// 1. Layout each child with a null or zero flex factor (e.g., those that are
5103/// not [Expanded]) with unbounded vertical constraints and the incoming
5104/// horizontal constraints. If the [crossAxisAlignment] is
5105/// [CrossAxisAlignment.stretch], instead use tight horizontal constraints
5106/// that match the incoming max width.
5107/// 2. Divide the remaining vertical space among the children with non-zero
5108/// flex factors (e.g., those that are [Expanded]) according to their flex
5109/// factor. For example, a child with a flex factor of 2.0 will receive twice
5110/// the amount of vertical space as a child with a flex factor of 1.0.
5111/// 3. Layout each of the remaining children with the same horizontal
5112/// constraints as in step 1, but instead of using unbounded vertical
5113/// constraints, use vertical constraints based on the amount of space
5114/// allocated in step 2. Children with [Flexible.fit] properties that are
5115/// [FlexFit.tight] are given tight constraints (i.e., forced to fill the
5116/// allocated space), and children with [Flexible.fit] properties that are
5117/// [FlexFit.loose] are given loose constraints (i.e., not forced to fill the
5118/// allocated space).
5119/// 4. The width of the [Column] is the maximum width of the children (which
5120/// will always satisfy the incoming horizontal constraints).
5121/// 5. The height of the [Column] is determined by the [mainAxisSize] property.
5122/// If the [mainAxisSize] property is [MainAxisSize.max], then the height of
5123/// the [Column] is the max height of the incoming constraints. If the
5124/// [mainAxisSize] property is [MainAxisSize.min], then the height of the
5125/// [Column] is the sum of heights of the children (subject to the incoming
5126/// constraints).
5127/// 6. Determine the position for each child according to the
5128/// [mainAxisAlignment] and the [crossAxisAlignment]. For example, if the
5129/// [mainAxisAlignment] is [MainAxisAlignment.spaceBetween], any vertical
5130/// space that has not been allocated to children is divided evenly and
5131/// placed between the children.
5132///
5133/// See also:
5134///
5135/// * [Row], for a horizontal equivalent.
5136/// * [Flex], if you don't know in advance if you want a horizontal or vertical
5137/// arrangement.
5138/// * [Expanded], to indicate children that should take all the remaining room.
5139/// * [Flexible], to indicate children that should share the remaining room but
5140/// that may size smaller (leaving some remaining room unused).
5141/// * [SingleChildScrollView], whose documentation discusses some ways to
5142/// use a [Column] inside a scrolling container.
5143/// * [Spacer], a widget that takes up space proportional to its flex value.
5144/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
5145class Column extends Flex {
5146 /// Creates a vertical array of children.
5147 ///
5148 /// If [crossAxisAlignment] is [CrossAxisAlignment.baseline], then
5149 /// [textBaseline] must not be null.
5150 ///
5151 /// The [textDirection] argument defaults to the ambient [Directionality], if
5152 /// any. If there is no ambient directionality, and a text direction is going
5153 /// to be necessary to disambiguate `start` or `end` values for the
5154 /// [crossAxisAlignment], the [textDirection] must not be null.
5155 const Column({
5156 super.key,
5157 super.mainAxisAlignment,
5158 super.mainAxisSize,
5159 super.crossAxisAlignment,
5160 super.textDirection,
5161 super.verticalDirection,
5162 super.textBaseline,
5163 super.children,
5164 }) : super(
5165 direction: Axis.vertical,
5166 );
5167}
5168
5169/// A widget that controls how a child of a [Row], [Column], or [Flex] flexes.
5170///
5171/// Using a [Flexible] widget gives a child of a [Row], [Column], or [Flex]
5172/// the flexibility to expand to fill the available space in the main axis
5173/// (e.g., horizontally for a [Row] or vertically for a [Column]), but, unlike
5174/// [Expanded], [Flexible] does not require the child to fill the available
5175/// space.
5176///
5177/// A [Flexible] widget must be a descendant of a [Row], [Column], or [Flex],
5178/// and the path from the [Flexible] widget to its enclosing [Row], [Column], or
5179/// [Flex] must contain only [StatelessWidget]s or [StatefulWidget]s (not other
5180/// kinds of widgets, like [RenderObjectWidget]s).
5181///
5182/// {@youtube 560 315 https://www.youtube.com/watch?v=CI7x0mAZiY0}
5183///
5184/// See also:
5185///
5186/// * [Expanded], which forces the child to expand to fill the available space.
5187/// * [Spacer], a widget that takes up space proportional to its flex value.
5188/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
5189class Flexible extends ParentDataWidget<FlexParentData> {
5190 /// Creates a widget that controls how a child of a [Row], [Column], or [Flex]
5191 /// flexes.
5192 const Flexible({
5193 super.key,
5194 this.flex = 1,
5195 this.fit = FlexFit.loose,
5196 required super.child,
5197 });
5198
5199 /// The flex factor to use for this child.
5200 ///
5201 /// If null or zero, the child is inflexible and determines its own size. If
5202 /// non-zero, the amount of space the child's can occupy in the main axis is
5203 /// determined by dividing the free space (after placing the inflexible
5204 /// children) according to the flex factors of the flexible children.
5205 final int flex;
5206
5207 /// How a flexible child is inscribed into the available space.
5208 ///
5209 /// If [flex] is non-zero, the [fit] determines whether the child fills the
5210 /// space the parent makes available during layout. If the fit is
5211 /// [FlexFit.tight], the child is required to fill the available space. If the
5212 /// fit is [FlexFit.loose], the child can be at most as large as the available
5213 /// space (but is allowed to be smaller).
5214 final FlexFit fit;
5215
5216 @override
5217 void applyParentData(RenderObject renderObject) {
5218 assert(renderObject.parentData is FlexParentData);
5219 final FlexParentData parentData = renderObject.parentData! as FlexParentData;
5220 bool needsLayout = false;
5221
5222 if (parentData.flex != flex) {
5223 parentData.flex = flex;
5224 needsLayout = true;
5225 }
5226
5227 if (parentData.fit != fit) {
5228 parentData.fit = fit;
5229 needsLayout = true;
5230 }
5231
5232 if (needsLayout) {
5233 final RenderObject? targetParent = renderObject.parent;
5234 if (targetParent is RenderObject) {
5235 targetParent.markNeedsLayout();
5236 }
5237 }
5238 }
5239
5240 @override
5241 Type get debugTypicalAncestorWidgetClass => Flex;
5242
5243 @override
5244 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
5245 super.debugFillProperties(properties);
5246 properties.add(IntProperty('flex', flex));
5247 }
5248}
5249
5250/// A widget that expands a child of a [Row], [Column], or [Flex]
5251/// so that the child fills the available space.
5252///
5253/// Using an [Expanded] widget makes a child of a [Row], [Column], or [Flex]
5254/// expand to fill the available space along the main axis (e.g., horizontally for
5255/// a [Row] or vertically for a [Column]). If multiple children are expanded,
5256/// the available space is divided among them according to the [flex] factor.
5257///
5258/// An [Expanded] widget must be a descendant of a [Row], [Column], or [Flex],
5259/// and the path from the [Expanded] widget to its enclosing [Row], [Column], or
5260/// [Flex] must contain only [StatelessWidget]s or [StatefulWidget]s (not other
5261/// kinds of widgets, like [RenderObjectWidget]s).
5262///
5263/// {@youtube 560 315 https://www.youtube.com/watch?v=_rnZaagadyo}
5264///
5265/// {@tool dartpad}
5266/// This example shows how to use an [Expanded] widget in a [Column] so that
5267/// its middle child, a [Container] here, expands to fill the space.
5268///
5269/// ![This results in two thin blue boxes with a larger amber box in between.](https://flutter.github.io/assets-for-api-docs/assets/widgets/expanded_column.png)
5270///
5271/// ** See code in examples/api/lib/widgets/basic/expanded.0.dart **
5272/// {@end-tool}
5273///
5274/// {@tool dartpad}
5275/// This example shows how to use an [Expanded] widget in a [Row] with multiple
5276/// children expanded, utilizing the [flex] factor to prioritize available space.
5277///
5278/// ![This results in a wide amber box, followed by a thin blue box, with a medium width amber box at the end.](https://flutter.github.io/assets-for-api-docs/assets/widgets/expanded_row.png)
5279///
5280/// ** See code in examples/api/lib/widgets/basic/expanded.1.dart **
5281/// {@end-tool}
5282///
5283/// See also:
5284///
5285/// * [Flexible], which does not force the child to fill the available space.
5286/// * [Spacer], a widget that takes up space proportional to its flex value.
5287/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
5288class Expanded extends Flexible {
5289 /// Creates a widget that expands a child of a [Row], [Column], or [Flex]
5290 /// so that the child fills the available space along the flex widget's
5291 /// main axis.
5292 const Expanded({
5293 super.key,
5294 super.flex,
5295 required super.child,
5296 }) : super(fit: FlexFit.tight);
5297}
5298
5299/// A widget that displays its children in multiple horizontal or vertical runs.
5300///
5301/// A [Wrap] lays out each child and attempts to place the child adjacent to the
5302/// previous child in the main axis, given by [direction], leaving [spacing]
5303/// space in between. If there is not enough space to fit the child, [Wrap]
5304/// creates a new _run_ adjacent to the existing children in the cross axis.
5305///
5306/// After all the children have been allocated to runs, the children within the
5307/// runs are positioned according to the [alignment] in the main axis and
5308/// according to the [crossAxisAlignment] in the cross axis.
5309///
5310/// The runs themselves are then positioned in the cross axis according to the
5311/// [runSpacing] and [runAlignment].
5312///
5313/// {@youtube 560 315 https://www.youtube.com/watch?v=z5iw2SeFx2M}
5314///
5315/// {@tool snippet}
5316///
5317/// This example renders some [Chip]s representing four contacts in a [Wrap] so
5318/// that they flow across lines as necessary.
5319///
5320/// ```dart
5321/// Wrap(
5322/// spacing: 8.0, // gap between adjacent chips
5323/// runSpacing: 4.0, // gap between lines
5324/// children: <Widget>[
5325/// Chip(
5326/// avatar: CircleAvatar(backgroundColor: Colors.blue.shade900, child: const Text('AH')),
5327/// label: const Text('Hamilton'),
5328/// ),
5329/// Chip(
5330/// avatar: CircleAvatar(backgroundColor: Colors.blue.shade900, child: const Text('ML')),
5331/// label: const Text('Lafayette'),
5332/// ),
5333/// Chip(
5334/// avatar: CircleAvatar(backgroundColor: Colors.blue.shade900, child: const Text('HM')),
5335/// label: const Text('Mulligan'),
5336/// ),
5337/// Chip(
5338/// avatar: CircleAvatar(backgroundColor: Colors.blue.shade900, child: const Text('JL')),
5339/// label: const Text('Laurens'),
5340/// ),
5341/// ],
5342/// )
5343/// ```
5344/// {@end-tool}
5345///
5346/// See also:
5347///
5348/// * [Row], which places children in one line, and gives control over their
5349/// alignment and spacing.
5350/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
5351class Wrap extends MultiChildRenderObjectWidget {
5352 /// Creates a wrap layout.
5353 ///
5354 /// By default, the wrap layout is horizontal and both the children and the
5355 /// runs are aligned to the start.
5356 ///
5357 /// The [textDirection] argument defaults to the ambient [Directionality], if
5358 /// any. If there is no ambient directionality, and a text direction is going
5359 /// to be necessary to decide which direction to lay the children in or to
5360 /// disambiguate `start` or `end` values for the main or cross axis
5361 /// directions, the [textDirection] must not be null.
5362 const Wrap({
5363 super.key,
5364 this.direction = Axis.horizontal,
5365 this.alignment = WrapAlignment.start,
5366 this.spacing = 0.0,
5367 this.runAlignment = WrapAlignment.start,
5368 this.runSpacing = 0.0,
5369 this.crossAxisAlignment = WrapCrossAlignment.start,
5370 this.textDirection,
5371 this.verticalDirection = VerticalDirection.down,
5372 this.clipBehavior = Clip.none,
5373 super.children,
5374 });
5375
5376 /// The direction to use as the main axis.
5377 ///
5378 /// For example, if [direction] is [Axis.horizontal], the default, the
5379 /// children are placed adjacent to one another in a horizontal run until the
5380 /// available horizontal space is consumed, at which point a subsequent
5381 /// children are placed in a new run vertically adjacent to the previous run.
5382 final Axis direction;
5383
5384 /// How the children within a run should be placed in the main axis.
5385 ///
5386 /// For example, if [alignment] is [WrapAlignment.center], the children in
5387 /// each run are grouped together in the center of their run in the main axis.
5388 ///
5389 /// Defaults to [WrapAlignment.start].
5390 ///
5391 /// See also:
5392 ///
5393 /// * [runAlignment], which controls how the runs are placed relative to each
5394 /// other in the cross axis.
5395 /// * [crossAxisAlignment], which controls how the children within each run
5396 /// are placed relative to each other in the cross axis.
5397 final WrapAlignment alignment;
5398
5399 /// How much space to place between children in a run in the main axis.
5400 ///
5401 /// For example, if [spacing] is 10.0, the children will be spaced at least
5402 /// 10.0 logical pixels apart in the main axis.
5403 ///
5404 /// If there is additional free space in a run (e.g., because the wrap has a
5405 /// minimum size that is not filled or because some runs are longer than
5406 /// others), the additional free space will be allocated according to the
5407 /// [alignment].
5408 ///
5409 /// Defaults to 0.0.
5410 final double spacing;
5411
5412 /// How the runs themselves should be placed in the cross axis.
5413 ///
5414 /// For example, if [runAlignment] is [WrapAlignment.center], the runs are
5415 /// grouped together in the center of the overall [Wrap] in the cross axis.
5416 ///
5417 /// Defaults to [WrapAlignment.start].
5418 ///
5419 /// See also:
5420 ///
5421 /// * [alignment], which controls how the children within each run are placed
5422 /// relative to each other in the main axis.
5423 /// * [crossAxisAlignment], which controls how the children within each run
5424 /// are placed relative to each other in the cross axis.
5425 final WrapAlignment runAlignment;
5426
5427 /// How much space to place between the runs themselves in the cross axis.
5428 ///
5429 /// For example, if [runSpacing] is 10.0, the runs will be spaced at least
5430 /// 10.0 logical pixels apart in the cross axis.
5431 ///
5432 /// If there is additional free space in the overall [Wrap] (e.g., because
5433 /// the wrap has a minimum size that is not filled), the additional free space
5434 /// will be allocated according to the [runAlignment].
5435 ///
5436 /// Defaults to 0.0.
5437 final double runSpacing;
5438
5439 /// How the children within a run should be aligned relative to each other in
5440 /// the cross axis.
5441 ///
5442 /// For example, if this is set to [WrapCrossAlignment.end], and the
5443 /// [direction] is [Axis.horizontal], then the children within each
5444 /// run will have their bottom edges aligned to the bottom edge of the run.
5445 ///
5446 /// Defaults to [WrapCrossAlignment.start].
5447 ///
5448 /// See also:
5449 ///
5450 /// * [alignment], which controls how the children within each run are placed
5451 /// relative to each other in the main axis.
5452 /// * [runAlignment], which controls how the runs are placed relative to each
5453 /// other in the cross axis.
5454 final WrapCrossAlignment crossAxisAlignment;
5455
5456 /// Determines the order to lay children out horizontally and how to interpret
5457 /// `start` and `end` in the horizontal direction.
5458 ///
5459 /// Defaults to the ambient [Directionality].
5460 ///
5461 /// If the [direction] is [Axis.horizontal], this controls order in which the
5462 /// children are positioned (left-to-right or right-to-left), and the meaning
5463 /// of the [alignment] property's [WrapAlignment.start] and
5464 /// [WrapAlignment.end] values.
5465 ///
5466 /// If the [direction] is [Axis.horizontal], and either the
5467 /// [alignment] is either [WrapAlignment.start] or [WrapAlignment.end], or
5468 /// there's more than one child, then the [textDirection] (or the ambient
5469 /// [Directionality]) must not be null.
5470 ///
5471 /// If the [direction] is [Axis.vertical], this controls the order in which
5472 /// runs are positioned, the meaning of the [runAlignment] property's
5473 /// [WrapAlignment.start] and [WrapAlignment.end] values, as well as the
5474 /// [crossAxisAlignment] property's [WrapCrossAlignment.start] and
5475 /// [WrapCrossAlignment.end] values.
5476 ///
5477 /// If the [direction] is [Axis.vertical], and either the
5478 /// [runAlignment] is either [WrapAlignment.start] or [WrapAlignment.end], the
5479 /// [crossAxisAlignment] is either [WrapCrossAlignment.start] or
5480 /// [WrapCrossAlignment.end], or there's more than one child, then the
5481 /// [textDirection] (or the ambient [Directionality]) must not be null.
5482 final TextDirection? textDirection;
5483
5484 /// Determines the order to lay children out vertically and how to interpret
5485 /// `start` and `end` in the vertical direction.
5486 ///
5487 /// If the [direction] is [Axis.vertical], this controls which order children
5488 /// are painted in (down or up), the meaning of the [alignment] property's
5489 /// [WrapAlignment.start] and [WrapAlignment.end] values.
5490 ///
5491 /// If the [direction] is [Axis.vertical], and either the [alignment]
5492 /// is either [WrapAlignment.start] or [WrapAlignment.end], or there's
5493 /// more than one child, then the [verticalDirection] must not be null.
5494 ///
5495 /// If the [direction] is [Axis.horizontal], this controls the order in which
5496 /// runs are positioned, the meaning of the [runAlignment] property's
5497 /// [WrapAlignment.start] and [WrapAlignment.end] values, as well as the
5498 /// [crossAxisAlignment] property's [WrapCrossAlignment.start] and
5499 /// [WrapCrossAlignment.end] values.
5500 ///
5501 /// If the [direction] is [Axis.horizontal], and either the
5502 /// [runAlignment] is either [WrapAlignment.start] or [WrapAlignment.end], the
5503 /// [crossAxisAlignment] is either [WrapCrossAlignment.start] or
5504 /// [WrapCrossAlignment.end], or there's more than one child, then the
5505 /// [verticalDirection] must not be null.
5506 final VerticalDirection verticalDirection;
5507
5508 /// {@macro flutter.material.Material.clipBehavior}
5509 ///
5510 /// Defaults to [Clip.none].
5511 final Clip clipBehavior;
5512
5513 @override
5514 RenderWrap createRenderObject(BuildContext context) {
5515 return RenderWrap(
5516 direction: direction,
5517 alignment: alignment,
5518 spacing: spacing,
5519 runAlignment: runAlignment,
5520 runSpacing: runSpacing,
5521 crossAxisAlignment: crossAxisAlignment,
5522 textDirection: textDirection ?? Directionality.maybeOf(context),
5523 verticalDirection: verticalDirection,
5524 clipBehavior: clipBehavior,
5525 );
5526 }
5527
5528 @override
5529 void updateRenderObject(BuildContext context, RenderWrap renderObject) {
5530 renderObject
5531 ..direction = direction
5532 ..alignment = alignment
5533 ..spacing = spacing
5534 ..runAlignment = runAlignment
5535 ..runSpacing = runSpacing
5536 ..crossAxisAlignment = crossAxisAlignment
5537 ..textDirection = textDirection ?? Directionality.maybeOf(context)
5538 ..verticalDirection = verticalDirection
5539 ..clipBehavior = clipBehavior;
5540 }
5541
5542 @override
5543 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
5544 super.debugFillProperties(properties);
5545 properties.add(EnumProperty<Axis>('direction', direction));
5546 properties.add(EnumProperty<WrapAlignment>('alignment', alignment));
5547 properties.add(DoubleProperty('spacing', spacing));
5548 properties.add(EnumProperty<WrapAlignment>('runAlignment', runAlignment));
5549 properties.add(DoubleProperty('runSpacing', runSpacing));
5550 properties.add(EnumProperty<WrapCrossAlignment>('crossAxisAlignment', crossAxisAlignment));
5551 properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
5552 properties.add(EnumProperty<VerticalDirection>('verticalDirection', verticalDirection, defaultValue: VerticalDirection.down));
5553 }
5554}
5555
5556/// A widget that sizes and positions children efficiently, according to the
5557/// logic in a [FlowDelegate].
5558///
5559/// {@youtube 560 315 https://www.youtube.com/watch?v=NG6pvXpnIso}
5560///
5561/// Flow layouts are optimized for repositioning children using transformation
5562/// matrices.
5563///
5564/// The flow container is sized independently from the children by the
5565/// [FlowDelegate.getSize] function of the delegate. The children are then sized
5566/// independently given the constraints from the
5567/// [FlowDelegate.getConstraintsForChild] function.
5568///
5569/// Rather than positioning the children during layout, the children are
5570/// positioned using transformation matrices during the paint phase using the
5571/// matrices from the [FlowDelegate.paintChildren] function. The children can be
5572/// repositioned efficiently by only _repainting_ the flow, which happens
5573/// without the children being laid out again (contrast this with a [Stack],
5574/// which does the sizing and positioning together during layout).
5575///
5576/// The most efficient way to trigger a repaint of the flow is to supply an
5577/// animation to the constructor of the [FlowDelegate]. The flow will listen to
5578/// this animation and repaint whenever the animation ticks, avoiding both the
5579/// build and layout phases of the pipeline.
5580///
5581/// {@tool dartpad}
5582/// This example uses the [Flow] widget to create a menu that opens and closes
5583/// as it is interacted with, shown above. The color of the button in the menu
5584/// changes to indicate which one has been selected.
5585///
5586/// ** See code in examples/api/lib/widgets/basic/flow.0.dart **
5587/// {@end-tool}
5588///
5589/// ## Hit testing and hidden [Flow] widgets
5590///
5591/// The [Flow] widget recomputes its children's positions (as used by hit
5592/// testing) during the _paint_ phase rather than during the _layout_ phase.
5593///
5594/// Widgets like [Opacity] avoid painting their children when those children
5595/// would be invisible due to their opacity being zero.
5596///
5597/// Unfortunately, this means that hiding a [Flow] widget using an [Opacity]
5598/// widget will cause bugs when the user attempts to interact with the hidden
5599/// region, for example, by tapping it or clicking it.
5600///
5601/// Such bugs will manifest either as out-of-date geometry (taps going to
5602/// different widgets than might be expected by the currently-specified
5603/// [FlowDelegate]s), or exceptions (e.g. if the last time the [Flow] was
5604/// painted, a different set of children was specified).
5605///
5606/// To avoid this, when hiding a [Flow] widget with an [Opacity] widget (or
5607/// [AnimatedOpacity] or similar), it is wise to also disable hit testing on the
5608/// widget by using [IgnorePointer]. This is generally good advice anyway as
5609/// hit-testing invisible widgets is often confusing for the user.
5610///
5611/// See also:
5612///
5613/// * [Wrap], which provides the layout model that some other frameworks call
5614/// "flow", and is otherwise unrelated to [Flow].
5615/// * [Stack], which arranges children relative to the edges of the container.
5616/// * [CustomSingleChildLayout], which uses a delegate to control the layout of
5617/// a single child.
5618/// * [CustomMultiChildLayout], which uses a delegate to position multiple
5619/// children.
5620/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
5621class Flow extends MultiChildRenderObjectWidget {
5622 /// Creates a flow layout.
5623 ///
5624 /// Wraps each of the given children in a [RepaintBoundary] to avoid
5625 /// repainting the children when the flow repaints.
5626 Flow({
5627 super.key,
5628 required this.delegate,
5629 List<Widget> children = const <Widget>[],
5630 this.clipBehavior = Clip.hardEdge,
5631 }) : super(children: RepaintBoundary.wrapAll(children));
5632 // https://github.com/dart-lang/sdk/issues/29277
5633
5634 /// Creates a flow layout.
5635 ///
5636 /// Does not wrap the given children in repaint boundaries, unlike the default
5637 /// constructor. Useful when the child is trivial to paint or already contains
5638 /// a repaint boundary.
5639 const Flow.unwrapped({
5640 super.key,
5641 required this.delegate,
5642 super.children,
5643 this.clipBehavior = Clip.hardEdge,
5644 });
5645
5646 /// The delegate that controls the transformation matrices of the children.
5647 final FlowDelegate delegate;
5648
5649 /// {@macro flutter.material.Material.clipBehavior}
5650 ///
5651 /// Defaults to [Clip.none].
5652 final Clip clipBehavior;
5653
5654 @override
5655 RenderFlow createRenderObject(BuildContext context) => RenderFlow(delegate: delegate, clipBehavior: clipBehavior);
5656
5657 @override
5658 void updateRenderObject(BuildContext context, RenderFlow renderObject) {
5659 renderObject.delegate = delegate;
5660 renderObject.clipBehavior = clipBehavior;
5661 }
5662}
5663
5664/// A paragraph of rich text.
5665///
5666/// {@youtube 560 315 https://www.youtube.com/watch?v=rykDVh-QFfw}
5667///
5668/// The [RichText] widget displays text that uses multiple different styles. The
5669/// text to display is described using a tree of [TextSpan] objects, each of
5670/// which has an associated style that is used for that subtree. The text might
5671/// break across multiple lines or might all be displayed on the same line
5672/// depending on the layout constraints.
5673///
5674/// Text displayed in a [RichText] widget must be explicitly styled. When
5675/// picking which style to use, consider using [DefaultTextStyle.of] the current
5676/// [BuildContext] to provide defaults. For more details on how to style text in
5677/// a [RichText] widget, see the documentation for [TextStyle].
5678///
5679/// Consider using the [Text] widget to integrate with the [DefaultTextStyle]
5680/// automatically. When all the text uses the same style, the default constructor
5681/// is less verbose. The [Text.rich] constructor allows you to style multiple
5682/// spans with the default text style while still allowing specified styles per
5683/// span.
5684///
5685/// {@tool snippet}
5686///
5687/// This sample demonstrates how to mix and match text with different text
5688/// styles using the [RichText] Widget. It displays the text "Hello bold world,"
5689/// emphasizing the word "bold" using a bold font weight.
5690///
5691/// ![](https://flutter.github.io/assets-for-api-docs/assets/widgets/rich_text.png)
5692///
5693/// ```dart
5694/// RichText(
5695/// text: TextSpan(
5696/// text: 'Hello ',
5697/// style: DefaultTextStyle.of(context).style,
5698/// children: const <TextSpan>[
5699/// TextSpan(text: 'bold', style: TextStyle(fontWeight: FontWeight.bold)),
5700/// TextSpan(text: ' world!'),
5701/// ],
5702/// ),
5703/// )
5704/// ```
5705/// {@end-tool}
5706///
5707/// ## Selections
5708///
5709/// To make this [RichText] Selectable, the [RichText] needs to be in the
5710/// subtree of a [SelectionArea] or [SelectableRegion] and a
5711/// [SelectionRegistrar] needs to be assigned to the
5712/// [RichText.selectionRegistrar]. One can use
5713/// [SelectionContainer.maybeOf] to get the [SelectionRegistrar] from a
5714/// context. This enables users to select the text in [RichText]s with mice or
5715/// touch events.
5716///
5717/// The [selectionColor] also needs to be set if the selection is enabled to
5718/// draw the selection highlights.
5719///
5720/// {@tool snippet}
5721///
5722/// This sample demonstrates how to assign a [SelectionRegistrar] for RichTexts
5723/// in the SelectionArea subtree.
5724///
5725/// ![](https://flutter.github.io/assets-for-api-docs/assets/widgets/rich_text.png)
5726///
5727/// ```dart
5728/// RichText(
5729/// text: const TextSpan(text: 'Hello'),
5730/// selectionRegistrar: SelectionContainer.maybeOf(context),
5731/// selectionColor: const Color(0xAF6694e8),
5732/// )
5733/// ```
5734/// {@end-tool}
5735///
5736/// See also:
5737///
5738/// * [TextStyle], which discusses how to style text.
5739/// * [TextSpan], which is used to describe the text in a paragraph.
5740/// * [Text], which automatically applies the ambient styles described by a
5741/// [DefaultTextStyle] to a single string.
5742/// * [Text.rich], a const text widget that provides similar functionality
5743/// as [RichText]. [Text.rich] will inherit [TextStyle] from [DefaultTextStyle].
5744/// * [SelectableRegion], which provides an overview of the selection system.
5745class RichText extends MultiChildRenderObjectWidget {
5746 /// Creates a paragraph of rich text.
5747 ///
5748 /// The [maxLines] property may be null (and indeed defaults to null), but if
5749 /// it is not null, it must be greater than zero.
5750 ///
5751 /// The [textDirection], if null, defaults to the ambient [Directionality],
5752 /// which in that case must not be null.
5753 RichText({
5754 super.key,
5755 required this.text,
5756 this.textAlign = TextAlign.start,
5757 this.textDirection,
5758 this.softWrap = true,
5759 this.overflow = TextOverflow.clip,
5760 @Deprecated(
5761 'Use textScaler instead. '
5762 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. '
5763 'This feature was deprecated after v3.12.0-2.0.pre.',
5764 )
5765 double textScaleFactor = 1.0,
5766 TextScaler textScaler = TextScaler.noScaling,
5767 this.maxLines,
5768 this.locale,
5769 this.strutStyle,
5770 this.textWidthBasis = TextWidthBasis.parent,
5771 this.textHeightBehavior,
5772 this.selectionRegistrar,
5773 this.selectionColor,
5774 }) : assert(maxLines == null || maxLines > 0),
5775 assert(selectionRegistrar == null || selectionColor != null),
5776 assert(textScaleFactor == 1.0 || identical(textScaler, TextScaler.noScaling), 'Use textScaler instead.'),
5777 textScaler = _effectiveTextScalerFrom(textScaler, textScaleFactor),
5778 super(children: WidgetSpan.extractFromInlineSpan(text, _effectiveTextScalerFrom(textScaler, textScaleFactor)));
5779
5780 static TextScaler _effectiveTextScalerFrom(TextScaler textScaler, double textScaleFactor) {
5781 return switch ((textScaler, textScaleFactor)) {
5782 (final TextScaler scaler, 1.0) => scaler,
5783 (TextScaler.noScaling, final double textScaleFactor) => TextScaler.linear(textScaleFactor),
5784 (final TextScaler scaler, _) => scaler,
5785 };
5786 }
5787
5788 /// The text to display in this widget.
5789 final InlineSpan text;
5790
5791 /// How the text should be aligned horizontally.
5792 final TextAlign textAlign;
5793
5794 /// The directionality of the text.
5795 ///
5796 /// This decides how [textAlign] values like [TextAlign.start] and
5797 /// [TextAlign.end] are interpreted.
5798 ///
5799 /// This is also used to disambiguate how to render bidirectional text. For
5800 /// example, if the [text] is an English phrase followed by a Hebrew phrase,
5801 /// in a [TextDirection.ltr] context the English phrase will be on the left
5802 /// and the Hebrew phrase to its right, while in a [TextDirection.rtl]
5803 /// context, the English phrase will be on the right and the Hebrew phrase on
5804 /// its left.
5805 ///
5806 /// Defaults to the ambient [Directionality], if any. If there is no ambient
5807 /// [Directionality], then this must not be null.
5808 final TextDirection? textDirection;
5809
5810 /// Whether the text should break at soft line breaks.
5811 ///
5812 /// If false, the glyphs in the text will be positioned as if there was unlimited horizontal space.
5813 final bool softWrap;
5814
5815 /// How visual overflow should be handled.
5816 final TextOverflow overflow;
5817
5818 /// Deprecated. Will be removed in a future version of Flutter. Use
5819 /// [textScaler] instead.
5820 ///
5821 /// The number of font pixels for each logical pixel.
5822 ///
5823 /// For example, if the text scale factor is 1.5, text will be 50% larger than
5824 /// the specified font size.
5825 @Deprecated(
5826 'Use textScaler instead. '
5827 'Use of textScaleFactor was deprecated in preparation for the upcoming nonlinear text scaling support. '
5828 'This feature was deprecated after v3.12.0-2.0.pre.',
5829 )
5830 double get textScaleFactor => textScaler.textScaleFactor;
5831
5832 /// {@macro flutter.painting.textPainter.textScaler}
5833 final TextScaler textScaler;
5834
5835 /// An optional maximum number of lines for the text to span, wrapping if necessary.
5836 /// If the text exceeds the given number of lines, it will be truncated according
5837 /// to [overflow].
5838 ///
5839 /// If this is 1, text will not wrap. Otherwise, text will be wrapped at the
5840 /// edge of the box.
5841 final int? maxLines;
5842
5843 /// Used to select a font when the same Unicode character can
5844 /// be rendered differently, depending on the locale.
5845 ///
5846 /// It's rarely necessary to set this property. By default its value
5847 /// is inherited from the enclosing app with `Localizations.localeOf(context)`.
5848 ///
5849 /// See [RenderParagraph.locale] for more information.
5850 final Locale? locale;
5851
5852 /// {@macro flutter.painting.textPainter.strutStyle}
5853 final StrutStyle? strutStyle;
5854
5855 /// {@macro flutter.painting.textPainter.textWidthBasis}
5856 final TextWidthBasis textWidthBasis;
5857
5858 /// {@macro dart.ui.textHeightBehavior}
5859 final ui.TextHeightBehavior? textHeightBehavior;
5860
5861 /// The [SelectionRegistrar] this rich text is subscribed to.
5862 ///
5863 /// If this is set, [selectionColor] must be non-null.
5864 final SelectionRegistrar? selectionRegistrar;
5865
5866 /// The color to use when painting the selection.
5867 ///
5868 /// This is ignored if [selectionRegistrar] is null.
5869 ///
5870 /// See the section on selections in the [RichText] top-level API
5871 /// documentation for more details on enabling selection in [RichText]
5872 /// widgets.
5873 final Color? selectionColor;
5874
5875 @override
5876 RenderParagraph createRenderObject(BuildContext context) {
5877 assert(textDirection != null || debugCheckHasDirectionality(context));
5878 return RenderParagraph(text,
5879 textAlign: textAlign,
5880 textDirection: textDirection ?? Directionality.of(context),
5881 softWrap: softWrap,
5882 overflow: overflow,
5883 textScaler: textScaler,
5884 maxLines: maxLines,
5885 strutStyle: strutStyle,
5886 textWidthBasis: textWidthBasis,
5887 textHeightBehavior: textHeightBehavior,
5888 locale: locale ?? Localizations.maybeLocaleOf(context),
5889 registrar: selectionRegistrar,
5890 selectionColor: selectionColor,
5891 );
5892 }
5893
5894 @override
5895 void updateRenderObject(BuildContext context, RenderParagraph renderObject) {
5896 assert(textDirection != null || debugCheckHasDirectionality(context));
5897 renderObject
5898 ..text = text
5899 ..textAlign = textAlign
5900 ..textDirection = textDirection ?? Directionality.of(context)
5901 ..softWrap = softWrap
5902 ..overflow = overflow
5903 ..textScaler = textScaler
5904 ..maxLines = maxLines
5905 ..strutStyle = strutStyle
5906 ..textWidthBasis = textWidthBasis
5907 ..textHeightBehavior = textHeightBehavior
5908 ..locale = locale ?? Localizations.maybeLocaleOf(context)
5909 ..registrar = selectionRegistrar
5910 ..selectionColor = selectionColor;
5911 }
5912
5913 @override
5914 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
5915 super.debugFillProperties(properties);
5916 properties.add(EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: TextAlign.start));
5917 properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
5918 properties.add(FlagProperty('softWrap', value: softWrap, ifTrue: 'wrapping at box width', ifFalse: 'no wrapping except at line break characters', showName: true));
5919 properties.add(EnumProperty<TextOverflow>('overflow', overflow, defaultValue: TextOverflow.clip));
5920 properties.add(DiagnosticsProperty<TextScaler>('textScaler', textScaler, defaultValue: TextScaler.noScaling));
5921 properties.add(IntProperty('maxLines', maxLines, ifNull: 'unlimited'));
5922 properties.add(EnumProperty<TextWidthBasis>('textWidthBasis', textWidthBasis, defaultValue: TextWidthBasis.parent));
5923 properties.add(StringProperty('text', text.toPlainText()));
5924 properties.add(DiagnosticsProperty<Locale>('locale', locale, defaultValue: null));
5925 properties.add(DiagnosticsProperty<StrutStyle>('strutStyle', strutStyle, defaultValue: null));
5926 properties.add(DiagnosticsProperty<TextHeightBehavior>('textHeightBehavior', textHeightBehavior, defaultValue: null));
5927 }
5928}
5929
5930/// A widget that displays a [dart:ui.Image] directly.
5931///
5932/// The image is painted using [paintImage], which describes the meanings of the
5933/// various fields on this class in more detail.
5934///
5935/// The [image] is not disposed of by this widget. Creators of the widget are
5936/// expected to call [Image.dispose] on the [image] once the [RawImage] is no
5937/// longer buildable.
5938///
5939/// This widget is rarely used directly. Instead, consider using [Image].
5940class RawImage extends LeafRenderObjectWidget {
5941 /// Creates a widget that displays an image.
5942 ///
5943 /// The [scale], [alignment], [repeat], [matchTextDirection] and [filterQuality] arguments must
5944 /// not be null.
5945 const RawImage({
5946 super.key,
5947 this.image,
5948 this.debugImageLabel,
5949 this.width,
5950 this.height,
5951 this.scale = 1.0,
5952 this.color,
5953 this.opacity,
5954 this.colorBlendMode,
5955 this.fit,
5956 this.alignment = Alignment.center,
5957 this.repeat = ImageRepeat.noRepeat,
5958 this.centerSlice,
5959 this.matchTextDirection = false,
5960 this.invertColors = false,
5961 this.filterQuality = FilterQuality.low,
5962 this.isAntiAlias = false,
5963 });
5964
5965 /// The image to display.
5966 ///
5967 /// Since a [RawImage] is stateless, it does not ever dispose this image.
5968 /// Creators of a [RawImage] are expected to call [Image.dispose] on this
5969 /// image handle when the [RawImage] will no longer be needed.
5970 final ui.Image? image;
5971
5972 /// A string identifying the source of the image.
5973 final String? debugImageLabel;
5974
5975 /// If non-null, require the image to have this width.
5976 ///
5977 /// If null, the image will pick a size that best preserves its intrinsic
5978 /// aspect ratio.
5979 final double? width;
5980
5981 /// If non-null, require the image to have this height.
5982 ///
5983 /// If null, the image will pick a size that best preserves its intrinsic
5984 /// aspect ratio.
5985 final double? height;
5986
5987 /// Specifies the image's scale.
5988 ///
5989 /// Used when determining the best display size for the image.
5990 final double scale;
5991
5992 /// If non-null, this color is blended with each image pixel using [colorBlendMode].
5993 final Color? color;
5994
5995 /// If non-null, the value from the [Animation] is multiplied with the opacity
5996 /// of each image pixel before painting onto the canvas.
5997 ///
5998 /// This is more efficient than using [FadeTransition] to change the opacity
5999 /// of an image.
6000 final Animation<double>? opacity;
6001
6002 /// Used to set the filterQuality of the image.
6003 ///
6004 /// Defaults to [FilterQuality.low] to scale the image, which corresponds to
6005 /// bilinear interpolation.
6006 final FilterQuality filterQuality;
6007
6008 /// Used to combine [color] with this image.
6009 ///
6010 /// The default is [BlendMode.srcIn]. In terms of the blend mode, [color] is
6011 /// the source and this image is the destination.
6012 ///
6013 /// See also:
6014 ///
6015 /// * [BlendMode], which includes an illustration of the effect of each blend mode.
6016 final BlendMode? colorBlendMode;
6017
6018 /// How to inscribe the image into the space allocated during layout.
6019 ///
6020 /// The default varies based on the other fields. See the discussion at
6021 /// [paintImage].
6022 final BoxFit? fit;
6023
6024 /// How to align the image within its bounds.
6025 ///
6026 /// The alignment aligns the given position in the image to the given position
6027 /// in the layout bounds. For example, an [Alignment] alignment of (-1.0,
6028 /// -1.0) aligns the image to the top-left corner of its layout bounds, while a
6029 /// [Alignment] alignment of (1.0, 1.0) aligns the bottom right of the
6030 /// image with the bottom right corner of its layout bounds. Similarly, an
6031 /// alignment of (0.0, 1.0) aligns the bottom middle of the image with the
6032 /// middle of the bottom edge of its layout bounds.
6033 ///
6034 /// To display a subpart of an image, consider using a [CustomPainter] and
6035 /// [Canvas.drawImageRect].
6036 ///
6037 /// If the [alignment] is [TextDirection]-dependent (i.e. if it is a
6038 /// [AlignmentDirectional]), then an ambient [Directionality] widget
6039 /// must be in scope.
6040 ///
6041 /// Defaults to [Alignment.center].
6042 ///
6043 /// See also:
6044 ///
6045 /// * [Alignment], a class with convenient constants typically used to
6046 /// specify an [AlignmentGeometry].
6047 /// * [AlignmentDirectional], like [Alignment] for specifying alignments
6048 /// relative to text direction.
6049 final AlignmentGeometry alignment;
6050
6051 /// How to paint any portions of the layout bounds not covered by the image.
6052 final ImageRepeat repeat;
6053
6054 /// The center slice for a nine-patch image.
6055 ///
6056 /// The region of the image inside the center slice will be stretched both
6057 /// horizontally and vertically to fit the image into its destination. The
6058 /// region of the image above and below the center slice will be stretched
6059 /// only horizontally and the region of the image to the left and right of
6060 /// the center slice will be stretched only vertically.
6061 final Rect? centerSlice;
6062
6063 /// Whether to paint the image in the direction of the [TextDirection].
6064 ///
6065 /// If this is true, then in [TextDirection.ltr] contexts, the image will be
6066 /// drawn with its origin in the top left (the "normal" painting direction for
6067 /// images); and in [TextDirection.rtl] contexts, the image will be drawn with
6068 /// a scaling factor of -1 in the horizontal direction so that the origin is
6069 /// in the top right.
6070 ///
6071 /// This is occasionally used with images in right-to-left environments, for
6072 /// images that were designed for left-to-right locales. Be careful, when
6073 /// using this, to not flip images with integral shadows, text, or other
6074 /// effects that will look incorrect when flipped.
6075 ///
6076 /// If this is true, there must be an ambient [Directionality] widget in
6077 /// scope.
6078 final bool matchTextDirection;
6079
6080 /// Whether the colors of the image are inverted when drawn.
6081 ///
6082 /// Inverting the colors of an image applies a new color filter to the paint.
6083 /// If there is another specified color filter, the invert will be applied
6084 /// after it. This is primarily used for implementing smart invert on iOS.
6085 ///
6086 /// See also:
6087 ///
6088 /// * [Paint.invertColors], for the dart:ui implementation.
6089 final bool invertColors;
6090
6091 /// Whether to paint the image with anti-aliasing.
6092 ///
6093 /// Anti-aliasing alleviates the sawtooth artifact when the image is rotated.
6094 final bool isAntiAlias;
6095
6096 @override
6097 RenderImage createRenderObject(BuildContext context) {
6098 assert((!matchTextDirection && alignment is Alignment) || debugCheckHasDirectionality(context));
6099 assert(
6100 image?.debugGetOpenHandleStackTraces()?.isNotEmpty ?? true,
6101 'Creator of a RawImage disposed of the image when the RawImage still '
6102 'needed it.',
6103 );
6104 return RenderImage(
6105 image: image?.clone(),
6106 debugImageLabel: debugImageLabel,
6107 width: width,
6108 height: height,
6109 scale: scale,
6110 color: color,
6111 opacity: opacity,
6112 colorBlendMode: colorBlendMode,
6113 fit: fit,
6114 alignment: alignment,
6115 repeat: repeat,
6116 centerSlice: centerSlice,
6117 matchTextDirection: matchTextDirection,
6118 textDirection: matchTextDirection || alignment is! Alignment ? Directionality.of(context) : null,
6119 invertColors: invertColors,
6120 isAntiAlias: isAntiAlias,
6121 filterQuality: filterQuality,
6122 );
6123 }
6124
6125 @override
6126 void updateRenderObject(BuildContext context, RenderImage renderObject) {
6127 assert(
6128 image?.debugGetOpenHandleStackTraces()?.isNotEmpty ?? true,
6129 'Creator of a RawImage disposed of the image when the RawImage still '
6130 'needed it.',
6131 );
6132 renderObject
6133 ..image = image?.clone()
6134 ..debugImageLabel = debugImageLabel
6135 ..width = width
6136 ..height = height
6137 ..scale = scale
6138 ..color = color
6139 ..opacity = opacity
6140 ..colorBlendMode = colorBlendMode
6141 ..fit = fit
6142 ..alignment = alignment
6143 ..repeat = repeat
6144 ..centerSlice = centerSlice
6145 ..matchTextDirection = matchTextDirection
6146 ..textDirection = matchTextDirection || alignment is! Alignment ? Directionality.of(context) : null
6147 ..invertColors = invertColors
6148 ..isAntiAlias = isAntiAlias
6149 ..filterQuality = filterQuality;
6150 }
6151
6152 @override
6153 void didUnmountRenderObject(RenderImage renderObject) {
6154 // Have the render object dispose its image handle.
6155 renderObject.image = null;
6156 }
6157
6158 @override
6159 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
6160 super.debugFillProperties(properties);
6161 properties.add(DiagnosticsProperty<ui.Image>('image', image));
6162 properties.add(DoubleProperty('width', width, defaultValue: null));
6163 properties.add(DoubleProperty('height', height, defaultValue: null));
6164 properties.add(DoubleProperty('scale', scale, defaultValue: 1.0));
6165 properties.add(ColorProperty('color', color, defaultValue: null));
6166 properties.add(DiagnosticsProperty<Animation<double>?>('opacity', opacity, defaultValue: null));
6167 properties.add(EnumProperty<BlendMode>('colorBlendMode', colorBlendMode, defaultValue: null));
6168 properties.add(EnumProperty<BoxFit>('fit', fit, defaultValue: null));
6169 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null));
6170 properties.add(EnumProperty<ImageRepeat>('repeat', repeat, defaultValue: ImageRepeat.noRepeat));
6171 properties.add(DiagnosticsProperty<Rect>('centerSlice', centerSlice, defaultValue: null));
6172 properties.add(FlagProperty('matchTextDirection', value: matchTextDirection, ifTrue: 'match text direction'));
6173 properties.add(DiagnosticsProperty<bool>('invertColors', invertColors));
6174 properties.add(EnumProperty<FilterQuality>('filterQuality', filterQuality));
6175 }
6176}
6177
6178/// A widget that determines the default asset bundle for its descendants.
6179///
6180/// For example, used by [Image] to determine which bundle to use for
6181/// [AssetImage]s if no bundle is specified explicitly.
6182///
6183/// {@tool snippet}
6184///
6185/// This can be used in tests to override what the current asset bundle is, thus
6186/// allowing specific resources to be injected into the widget under test.
6187///
6188/// For example, a test could create a test asset bundle like this:
6189///
6190/// ```dart