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
6191/// class TestAssetBundle extends CachingAssetBundle {
6192/// @override
6193/// Future<ByteData> load(String key) async {
6194/// if (key == 'resources/test') {
6195/// return ByteData.sublistView(utf8.encode('Hello World!'));
6196/// }
6197/// return ByteData(0);
6198/// }
6199/// }
6200/// ```
6201/// {@end-tool}
6202/// {@tool snippet}
6203///
6204/// ...then wrap the widget under test with a [DefaultAssetBundle] using this
6205/// bundle implementation:
6206///
6207/// ```dart
6208/// // continuing from previous example...
6209/// await tester.pumpWidget(
6210/// MaterialApp(
6211/// home: DefaultAssetBundle(
6212/// bundle: TestAssetBundle(),
6213/// child: const TestWidget(),
6214/// ),
6215/// ),
6216/// );
6217/// ```
6218/// {@end-tool}
6219///
6220/// Assuming that `TestWidget` uses [DefaultAssetBundle.of] to obtain its
6221/// [AssetBundle], it will now see the `TestAssetBundle`'s "Hello World!" data
6222/// when requesting the "resources/test" asset.
6223///
6224/// See also:
6225///
6226/// * [AssetBundle], the interface for asset bundles.
6227/// * [rootBundle], the default asset bundle.
6228class DefaultAssetBundle extends InheritedWidget {
6229 /// Creates a widget that determines the default asset bundle for its descendants.
6230 const DefaultAssetBundle({
6231 super.key,
6232 required this.bundle,
6233 required super.child,
6234 });
6235
6236 /// The bundle to use as a default.
6237 final AssetBundle bundle;
6238
6239 /// The bundle from the closest instance of this class that encloses
6240 /// the given context.
6241 ///
6242 /// If there is no [DefaultAssetBundle] ancestor widget in the tree
6243 /// at the given context, then this will return the [rootBundle].
6244 ///
6245 /// Typical usage is as follows:
6246 ///
6247 /// ```dart
6248 /// AssetBundle bundle = DefaultAssetBundle.of(context);
6249 /// ```
6250 static AssetBundle of(BuildContext context) {
6251 final DefaultAssetBundle? result = context.dependOnInheritedWidgetOfExactType<DefaultAssetBundle>();
6252 return result?.bundle ?? rootBundle;
6253 }
6254
6255 @override
6256 bool updateShouldNotify(DefaultAssetBundle oldWidget) => bundle != oldWidget.bundle;
6257}
6258
6259/// An adapter for placing a specific [RenderBox] in the widget tree.
6260///
6261/// A given render object can be placed at most once in the widget tree. This
6262/// widget enforces that restriction by keying itself using a [GlobalObjectKey]
6263/// for the given render object.
6264///
6265/// This widget will call [RenderObject.dispose] on the [renderBox] when it is
6266/// unmounted. After that point, the [renderBox] will be unusable. If any
6267/// children have been added to the [renderBox], they must be disposed in the
6268/// [onUnmount] callback.
6269class WidgetToRenderBoxAdapter extends LeafRenderObjectWidget {
6270 /// Creates an adapter for placing a specific [RenderBox] in the widget tree.
6271 WidgetToRenderBoxAdapter({
6272 required this.renderBox,
6273 this.onBuild,
6274 this.onUnmount,
6275 }) : super(key: GlobalObjectKey(renderBox));
6276
6277 /// The render box to place in the widget tree.
6278 ///
6279 /// This widget takes ownership of the render object. When it is unmounted,
6280 /// it also calls [RenderObject.dispose].
6281 final RenderBox renderBox;
6282
6283 /// Called when it is safe to update the render box and its descendants. If
6284 /// you update the RenderObject subtree under this widget outside of
6285 /// invocations of this callback, features like hit-testing will fail as the
6286 /// tree will be dirty.
6287 final VoidCallback? onBuild;
6288
6289 /// Called when it is safe to dispose of children that were manually added to
6290 /// the [renderBox].
6291 ///
6292 /// Do not dispose the [renderBox] itself, as it will be disposed by the
6293 /// framework automatically. However, during that process the framework will
6294 /// check that all children of the [renderBox] have also been disposed.
6295 /// Typically, child [RenderObject]s are disposed by corresponding [Element]s
6296 /// when they are unmounted. However, child render objects that were manually
6297 /// added do not have corresponding [Element]s to manage their lifecycle, and
6298 /// need to be manually disposed here.
6299 ///
6300 /// See also:
6301 ///
6302 /// * [RenderObjectElement.unmount], which invokes this callback before
6303 /// disposing of its render object.
6304 /// * [RenderObject.dispose], which instructs a render object to release
6305 /// any resources it may be holding.
6306 final VoidCallback? onUnmount;
6307
6308 @override
6309 RenderBox createRenderObject(BuildContext context) => renderBox;
6310
6311 @override
6312 void updateRenderObject(BuildContext context, RenderBox renderObject) {
6313 onBuild?.call();
6314 }
6315
6316 @override
6317 void didUnmountRenderObject(RenderObject renderObject) {
6318 assert(renderObject == renderBox);
6319 onUnmount?.call();
6320 }
6321}
6322
6323
6324// EVENT HANDLING
6325
6326/// A widget that calls callbacks in response to common pointer events.
6327///
6328/// It listens to events that can construct gestures, such as when the
6329/// pointer is pressed, moved, then released or canceled.
6330///
6331/// It does not listen to events that are exclusive to mouse, such as when the
6332/// mouse enters, exits or hovers a region without pressing any buttons. For
6333/// these events, use [MouseRegion].
6334///
6335/// Rather than listening for raw pointer events, consider listening for
6336/// higher-level gestures using [GestureDetector].
6337///
6338/// ## Layout behavior
6339///
6340/// _See [BoxConstraints] for an introduction to box layout models._
6341///
6342/// If it has a child, this widget defers to the child for sizing behavior. If
6343/// it does not have a child, it grows to fit the parent instead.
6344///
6345/// {@tool dartpad}
6346/// This example makes a [Container] react to being touched, showing a count of
6347/// the number of pointer downs and ups.
6348///
6349/// ** See code in examples/api/lib/widgets/basic/listener.0.dart **
6350/// {@end-tool}
6351class Listener extends SingleChildRenderObjectWidget {
6352 /// Creates a widget that forwards point events to callbacks.
6353 ///
6354 /// The [behavior] argument defaults to [HitTestBehavior.deferToChild].
6355 const Listener({
6356 super.key,
6357 this.onPointerDown,
6358 this.onPointerMove,
6359 this.onPointerUp,
6360 this.onPointerHover,
6361 this.onPointerCancel,
6362 this.onPointerPanZoomStart,
6363 this.onPointerPanZoomUpdate,
6364 this.onPointerPanZoomEnd,
6365 this.onPointerSignal,
6366 this.behavior = HitTestBehavior.deferToChild,
6367 super.child,
6368 });
6369
6370 /// Called when a pointer comes into contact with the screen (for touch
6371 /// pointers), or has its button pressed (for mouse pointers) at this widget's
6372 /// location.
6373 final PointerDownEventListener? onPointerDown;
6374
6375 /// Called when a pointer that triggered an [onPointerDown] changes position.
6376 final PointerMoveEventListener? onPointerMove;
6377
6378 /// Called when a pointer that triggered an [onPointerDown] is no longer in
6379 /// contact with the screen.
6380 final PointerUpEventListener? onPointerUp;
6381
6382 /// Called when a pointer that has not triggered an [onPointerDown] changes
6383 /// position.
6384 ///
6385 /// This is only fired for pointers which report their location when not down
6386 /// (e.g. mouse pointers, but not most touch pointers).
6387 final PointerHoverEventListener? onPointerHover;
6388
6389 /// Called when the input from a pointer that triggered an [onPointerDown] is
6390 /// no longer directed towards this receiver.
6391 final PointerCancelEventListener? onPointerCancel;
6392
6393 /// Called when a pan/zoom begins such as from a trackpad gesture.
6394 final PointerPanZoomStartEventListener? onPointerPanZoomStart;
6395
6396 /// Called when a pan/zoom is updated.
6397 final PointerPanZoomUpdateEventListener? onPointerPanZoomUpdate;
6398
6399 /// Called when a pan/zoom finishes.
6400 final PointerPanZoomEndEventListener? onPointerPanZoomEnd;
6401
6402 /// Called when a pointer signal occurs over this object.
6403 ///
6404 /// See also:
6405 ///
6406 /// * [PointerSignalEvent], which goes into more detail on pointer signal
6407 /// events.
6408 final PointerSignalEventListener? onPointerSignal;
6409
6410 /// How to behave during hit testing.
6411 final HitTestBehavior behavior;
6412
6413 @override
6414 RenderPointerListener createRenderObject(BuildContext context) {
6415 return RenderPointerListener(
6416 onPointerDown: onPointerDown,
6417 onPointerMove: onPointerMove,
6418 onPointerUp: onPointerUp,
6419 onPointerHover: onPointerHover,
6420 onPointerCancel: onPointerCancel,
6421 onPointerPanZoomStart: onPointerPanZoomStart,
6422 onPointerPanZoomUpdate: onPointerPanZoomUpdate,
6423 onPointerPanZoomEnd: onPointerPanZoomEnd,
6424 onPointerSignal: onPointerSignal,
6425 behavior: behavior,
6426 );
6427 }
6428
6429 @override
6430 void updateRenderObject(BuildContext context, RenderPointerListener renderObject) {
6431 renderObject
6432 ..onPointerDown = onPointerDown
6433 ..onPointerMove = onPointerMove
6434 ..onPointerUp = onPointerUp
6435 ..onPointerHover = onPointerHover
6436 ..onPointerCancel = onPointerCancel
6437 ..onPointerPanZoomStart = onPointerPanZoomStart
6438 ..onPointerPanZoomUpdate = onPointerPanZoomUpdate
6439 ..onPointerPanZoomEnd = onPointerPanZoomEnd
6440 ..onPointerSignal = onPointerSignal
6441 ..behavior = behavior;
6442 }
6443
6444 @override
6445 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
6446 super.debugFillProperties(properties);
6447 final List<String> listeners = <String>[
6448 if (onPointerDown != null) 'down',
6449 if (onPointerMove != null) 'move',
6450 if (onPointerUp != null) 'up',
6451 if (onPointerHover != null) 'hover',
6452 if (onPointerCancel != null) 'cancel',
6453 if (onPointerPanZoomStart != null) 'panZoomStart',
6454 if (onPointerPanZoomUpdate != null) 'panZoomUpdate',
6455 if (onPointerPanZoomEnd != null) 'panZoomEnd',
6456 if (onPointerSignal != null) 'signal',
6457 ];
6458 properties.add(IterableProperty<String>('listeners', listeners, ifEmpty: '<none>'));
6459 properties.add(EnumProperty<HitTestBehavior>('behavior', behavior));
6460 }
6461}
6462
6463/// A widget that tracks the movement of mice.
6464///
6465/// {@youtube 560 315 https://www.youtube.com/watch?v=1oF3pI5umck}
6466///
6467/// [MouseRegion] is used
6468/// when it is needed to compare the list of objects that a mouse pointer is
6469/// hovering over between this frame and the last frame. This means entering
6470/// events, exiting events, and mouse cursors.
6471///
6472/// To listen to general pointer events, use [Listener], or more preferably,
6473/// [GestureDetector].
6474///
6475/// ## Layout behavior
6476///
6477/// _See [BoxConstraints] for an introduction to box layout models._
6478///
6479/// If it has a child, this widget defers to the child for sizing behavior. If
6480/// it does not have a child, it grows to fit the parent instead.
6481///
6482/// {@tool dartpad}
6483/// This example makes a [Container] react to being entered by a mouse
6484/// pointer, showing a count of the number of entries and exits.
6485///
6486/// ** See code in examples/api/lib/widgets/basic/mouse_region.0.dart **
6487/// {@end-tool}
6488///
6489/// See also:
6490///
6491/// * [Listener], a similar widget that tracks pointer events when the pointer
6492/// has buttons pressed.
6493class MouseRegion extends SingleChildRenderObjectWidget {
6494 /// Creates a widget that forwards mouse events to callbacks.
6495 ///
6496 /// By default, all callbacks are empty, [cursor] is [MouseCursor.defer], and
6497 /// [opaque] is true.
6498 const MouseRegion({
6499 super.key,
6500 this.onEnter,
6501 this.onExit,
6502 this.onHover,
6503 this.cursor = MouseCursor.defer,
6504 this.opaque = true,
6505 this.hitTestBehavior,
6506 super.child,
6507 });
6508
6509 /// Triggered when a mouse pointer has entered this widget.
6510 ///
6511 /// This callback is triggered when the pointer, with or without buttons
6512 /// pressed, has started to be contained by the region of this widget. More
6513 /// specifically, the callback is triggered by the following cases:
6514 ///
6515 /// * This widget has appeared under a pointer.
6516 /// * This widget has moved to under a pointer.
6517 /// * A new pointer has been added to somewhere within this widget.
6518 /// * An existing pointer has moved into this widget.
6519 ///
6520 /// This callback is not always matched by an [onExit]. If the [MouseRegion]
6521 /// is unmounted while being hovered by a pointer, the [onExit] of the widget
6522 /// callback will never called. For more details, see [onExit].
6523 ///
6524 /// {@template flutter.widgets.MouseRegion.onEnter.triggerTime}
6525 /// The time that this callback is triggered is always between frames: either
6526 /// during the post-frame callbacks, or during the callback of a pointer
6527 /// event.
6528 /// {@endtemplate}
6529 ///
6530 /// See also:
6531 ///
6532 /// * [onExit], which is triggered when a mouse pointer exits the region.
6533 /// * [MouseTrackerAnnotation.onEnter], which is how this callback is
6534 /// internally implemented.
6535 final PointerEnterEventListener? onEnter;
6536
6537 /// Triggered when a pointer moves into a position within this widget without
6538 /// buttons pressed.
6539 ///
6540 /// Usually this is only fired for pointers which report their location when
6541 /// not down (e.g. mouse pointers). Certain devices also fire this event on
6542 /// single taps in accessibility mode.
6543 ///
6544 /// This callback is not triggered by the movement of the widget.
6545 ///
6546 /// The time that this callback is triggered is during the callback of a
6547 /// pointer event, which is always between frames.
6548 ///
6549 /// See also:
6550 ///
6551 /// * [Listener.onPointerHover], which does the same job. Prefer using
6552 /// [Listener.onPointerHover], since hover events are similar to other regular
6553 /// events.
6554 final PointerHoverEventListener? onHover;
6555
6556 /// Triggered when a mouse pointer has exited this widget when the widget is
6557 /// still mounted.
6558 ///
6559 /// This callback is triggered when the pointer, with or without buttons
6560 /// pressed, has stopped being contained by the region of this widget, except
6561 /// when the exit is caused by the disappearance of this widget. More
6562 /// specifically, this callback is triggered by the following cases:
6563 ///
6564 /// * A pointer that is hovering this widget has moved away.
6565 /// * A pointer that is hovering this widget has been removed.
6566 /// * This widget, which is being hovered by a pointer, has moved away.
6567 ///
6568 /// And is __not__ triggered by the following case:
6569 ///
6570 /// * This widget, which is being hovered by a pointer, has disappeared.
6571 ///
6572 /// This means that a [MouseRegion.onExit] might not be matched by a
6573 /// [MouseRegion.onEnter].
6574 ///
6575 /// This restriction aims to prevent a common misuse: if [State.setState] is
6576 /// called during [MouseRegion.onExit] without checking whether the widget is
6577 /// still mounted, an exception will occur. This is because the callback is
6578 /// triggered during the post-frame phase, at which point the widget has been
6579 /// unmounted. Since [State.setState] is exclusive to widgets, the restriction
6580 /// is specific to [MouseRegion], and does not apply to its lower-level
6581 /// counterparts, [RenderMouseRegion] and [MouseTrackerAnnotation].
6582 ///
6583 /// There are a few ways to mitigate this restriction:
6584 ///
6585 /// * If the hover state is completely contained within a widget that
6586 /// unconditionally creates this [MouseRegion], then this will not be a
6587 /// concern, since after the [MouseRegion] is unmounted the state is no
6588 /// longer used.
6589 /// * Otherwise, the outer widget very likely has access to the variable that
6590 /// controls whether this [MouseRegion] is present. If so, call [onExit] at
6591 /// the event that turns the condition from true to false.
6592 /// * In cases where the solutions above won't work, you can always
6593 /// override [State.dispose] and call [onExit], or create your own widget
6594 /// using [RenderMouseRegion].
6595 ///
6596 /// {@tool dartpad}
6597 /// The following example shows a blue rectangular that turns yellow when
6598 /// hovered. Since the hover state is completely contained within a widget
6599 /// that unconditionally creates the `MouseRegion`, you can ignore the
6600 /// aforementioned restriction.
6601 ///
6602 /// ** See code in examples/api/lib/widgets/basic/mouse_region.on_exit.0.dart **
6603 /// {@end-tool}
6604 ///
6605 /// {@tool dartpad}
6606 /// The following example shows a widget that hides its content one second
6607 /// after being hovered, and also exposes the enter and exit callbacks.
6608 /// Because the widget conditionally creates the `MouseRegion`, and leaks the
6609 /// hover state, it needs to take the restriction into consideration. In this
6610 /// case, since it has access to the event that triggers the disappearance of
6611 /// the `MouseRegion`, it triggers the exit callback during that event
6612 /// as well.
6613 ///
6614 /// ** See code in examples/api/lib/widgets/basic/mouse_region.on_exit.1.dart **
6615 /// {@end-tool}
6616 ///
6617 /// {@macro flutter.widgets.MouseRegion.onEnter.triggerTime}
6618 ///
6619 /// See also:
6620 ///
6621 /// * [onEnter], which is triggered when a mouse pointer enters the region.
6622 /// * [RenderMouseRegion] and [MouseTrackerAnnotation.onExit], which are how
6623 /// this callback is internally implemented, but without the restriction.
6624 final PointerExitEventListener? onExit;
6625
6626 /// The mouse cursor for mouse pointers that are hovering over the region.
6627 ///
6628 /// When a mouse enters the region, its cursor will be changed to the [cursor].
6629 /// When the mouse leaves the region, the cursor will be decided by the region
6630 /// found at the new location.
6631 ///
6632 /// The [cursor] defaults to [MouseCursor.defer], deferring the choice of
6633 /// cursor to the next region behind it in hit-test order.
6634 final MouseCursor cursor;
6635
6636 /// Whether this widget should prevent other [MouseRegion]s visually behind it
6637 /// from detecting the pointer.
6638 ///
6639 /// This changes the list of regions that a pointer hovers, thus affecting how
6640 /// their [onHover], [onEnter], [onExit], and [cursor] behave.
6641 ///
6642 /// If [opaque] is true, this widget will absorb the mouse pointer and
6643 /// prevent this widget's siblings (or any other widgets that are not
6644 /// ancestors or descendants of this widget) from detecting the mouse
6645 /// pointer even when the pointer is within their areas.
6646 ///
6647 /// If [opaque] is false, this object will not affect how [MouseRegion]s
6648 /// behind it behave, which will detect the mouse pointer as long as the
6649 /// pointer is within their areas.
6650 ///
6651 /// This defaults to true.
6652 final bool opaque;
6653
6654 /// How to behave during hit testing.
6655 ///
6656 /// This defaults to [HitTestBehavior.opaque] if null.
6657 final HitTestBehavior? hitTestBehavior;
6658
6659 @override
6660 RenderMouseRegion createRenderObject(BuildContext context) {
6661 return RenderMouseRegion(
6662 onEnter: onEnter,
6663 onHover: onHover,
6664 onExit: onExit,
6665 cursor: cursor,
6666 opaque: opaque,
6667 hitTestBehavior: hitTestBehavior,
6668 );
6669 }
6670
6671 @override
6672 void updateRenderObject(BuildContext context, RenderMouseRegion renderObject) {
6673 renderObject
6674 ..onEnter = onEnter
6675 ..onHover = onHover
6676 ..onExit = onExit
6677 ..cursor = cursor
6678 ..opaque = opaque
6679 ..hitTestBehavior = hitTestBehavior;
6680 }
6681
6682 @override
6683 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
6684 super.debugFillProperties(properties);
6685 final List<String> listeners = <String>[];
6686 if (onEnter != null) {
6687 listeners.add('enter');
6688 }
6689 if (onExit != null) {
6690 listeners.add('exit');
6691 }
6692 if (onHover != null) {
6693 listeners.add('hover');
6694 }
6695 properties.add(IterableProperty<String>('listeners', listeners, ifEmpty: '<none>'));
6696 properties.add(DiagnosticsProperty<MouseCursor>('cursor', cursor, defaultValue: null));
6697 properties.add(DiagnosticsProperty<bool>('opaque', opaque, defaultValue: true));
6698 }
6699}
6700
6701/// A widget that creates a separate display list for its child.
6702///
6703/// {@youtube 560 315 https://www.youtube.com/watch?v=cVAGLDuc2xE}
6704///
6705/// This widget creates a separate display list for its child, which
6706/// can improve performance if the subtree repaints at different times than
6707/// the surrounding parts of the tree.
6708///
6709/// This is useful since [RenderObject.paint] may be triggered even if its
6710/// associated [Widget] instances did not change or rebuild. A [RenderObject]
6711/// will repaint whenever any [RenderObject] that shares the same [Layer] is
6712/// marked as being dirty and needing paint (see [RenderObject.markNeedsPaint]),
6713/// such as when an ancestor scrolls or when an ancestor or descendant animates.
6714///
6715/// Containing [RenderObject.paint] to parts of the render subtree that are
6716/// actually visually changing using [RepaintBoundary] explicitly or implicitly
6717/// is therefore critical to minimizing redundant work and improving the app's
6718/// performance.
6719///
6720/// When a [RenderObject] is flagged as needing to paint via
6721/// [RenderObject.markNeedsPaint], the nearest ancestor [RenderObject] with
6722/// [RenderObject.isRepaintBoundary], up to possibly the root of the application,
6723/// is requested to repaint. That nearest ancestor's [RenderObject.paint] method
6724/// will cause _all_ of its descendant [RenderObject]s to repaint in the same
6725/// layer.
6726///
6727/// [RepaintBoundary] is therefore used, both while propagating the
6728/// `markNeedsPaint` flag up the render tree and while traversing down the
6729/// render tree via [PaintingContext.paintChild], to strategically contain
6730/// repaints to the render subtree that visually changed for performance. This
6731/// is done because the [RepaintBoundary] widget creates a [RenderObject] that
6732/// always has a [Layer], decoupling ancestor render objects from the descendant
6733/// render objects.
6734///
6735/// [RepaintBoundary] has the further side-effect of possibly hinting to the
6736/// engine that it should further optimize animation performance if the render
6737/// subtree behind the [RepaintBoundary] is sufficiently complex and is static
6738/// while the surrounding tree changes frequently. In those cases, the engine
6739/// may choose to pay a one time cost of rasterizing and caching the pixel
6740/// values of the subtree for faster future GPU re-rendering speed.
6741///
6742/// Several framework widgets insert [RepaintBoundary] widgets to mark natural
6743/// separation points in applications. For instance, contents in Material Design
6744/// drawers typically don't change while the drawer opens and closes, so
6745/// repaints are automatically contained to regions inside or outside the drawer
6746/// when using the [Drawer] widget during transitions.
6747///
6748/// See also:
6749///
6750/// * [debugRepaintRainbowEnabled], a debugging flag to help visually monitor
6751/// render tree repaints in a running app.
6752/// * [debugProfilePaintsEnabled], a debugging flag to show render tree
6753/// repaints in the observatory's timeline view.
6754class RepaintBoundary extends SingleChildRenderObjectWidget {
6755 /// Creates a widget that isolates repaints.
6756 const RepaintBoundary({ super.key, super.child });
6757
6758 /// Wraps the given child in a [RepaintBoundary].
6759 ///
6760 /// The key for the [RepaintBoundary] is derived either from the child's key
6761 /// (if the child has a non-null key) or from the given `childIndex`.
6762 factory RepaintBoundary.wrap(Widget child, int childIndex) {
6763 final Key key = child.key != null ? ValueKey<Key>(child.key!) : ValueKey<int>(childIndex);
6764 return RepaintBoundary(key: key, child: child);
6765 }
6766
6767 /// Wraps each of the given children in [RepaintBoundary]s.
6768 ///
6769 /// The key for each [RepaintBoundary] is derived either from the wrapped
6770 /// child's key (if the wrapped child has a non-null key) or from the wrapped
6771 /// child's index in the list.
6772 static List<RepaintBoundary> wrapAll(List<Widget> widgets) => <RepaintBoundary>[
6773 for (int i = 0; i < widgets.length; ++i) RepaintBoundary.wrap(widgets[i], i),
6774 ];
6775
6776 @override
6777 RenderRepaintBoundary createRenderObject(BuildContext context) => RenderRepaintBoundary();
6778}
6779
6780/// A widget that is invisible during hit testing.
6781///
6782/// When [ignoring] is true, this widget (and its subtree) is invisible
6783/// to hit testing. It still consumes space during layout and paints its child
6784/// as usual. It just cannot be the target of located events, because it returns
6785/// false from [RenderBox.hitTest].
6786///
6787/// {@youtube 560 315 https://www.youtube.com/watch?v=qV9pqHWxYgI}
6788///
6789/// {@tool dartpad}
6790/// The following sample has an [IgnorePointer] widget wrapping the `Column`
6791/// which contains a button.
6792/// When [ignoring] is set to `true` anything inside the `Column` can
6793/// not be tapped. When [ignoring] is set to `false` anything
6794/// inside the `Column` can be tapped.
6795///
6796/// ** See code in examples/api/lib/widgets/basic/ignore_pointer.0.dart **
6797/// {@end-tool}
6798///
6799/// ## Semantics
6800///
6801/// Using this class may also affect how the semantics subtree underneath is
6802/// collected.
6803///
6804/// {@template flutter.widgets.IgnorePointer.semantics}
6805/// If [ignoring] is true, pointer-related [SemanticsAction]s are removed from
6806/// the semantics subtree. Otherwise, the subtree remains untouched.
6807/// {@endtemplate}
6808///
6809/// {@template flutter.widgets.IgnorePointer.ignoringSemantics}
6810/// The usages of [ignoringSemantics] are deprecated and not recommended. This
6811/// property was introduced to workaround the semantics behavior of the
6812/// [IgnorePointer] and its friends before v3.8.0-12.0.pre.
6813///
6814/// Before that version, entire semantics subtree is dropped if [ignoring] is
6815/// true. Developers can only use [ignoringSemantics] to preserver the semantics
6816/// subtrees.
6817///
6818/// After that version, with [ignoring] set to true, it only prevents semantics
6819/// user actions in the semantics subtree but leaves the other
6820/// [SemanticsProperties] intact. Therefore, the [ignoringSemantics] is no
6821/// longer needed.
6822///
6823/// If [ignoringSemantics] is true, the semantics subtree is dropped. Therefore,
6824/// the subtree will be invisible to assistive technologies.
6825///
6826/// If [ignoringSemantics] is false, the semantics subtree is collected as
6827/// usual.
6828/// {@endtemplate}
6829///
6830/// See also:
6831///
6832/// * [AbsorbPointer], which also prevents its children from receiving pointer
6833/// events but is itself visible to hit testing.
6834/// * [SliverIgnorePointer], the sliver version of this widget.
6835class IgnorePointer extends SingleChildRenderObjectWidget {
6836 /// Creates a widget that is invisible to hit testing.
6837 const IgnorePointer({
6838 super.key,
6839 this.ignoring = true,
6840 @Deprecated(
6841 'Use ExcludeSemantics or create a custom ignore pointer widget instead. '
6842 'This feature was deprecated after v3.8.0-12.0.pre.'
6843 )
6844 this.ignoringSemantics,
6845 super.child,
6846 });
6847
6848 /// Whether this widget is ignored during hit testing.
6849 ///
6850 /// Regardless of whether this widget is ignored during hit testing, it will
6851 /// still consume space during layout and be visible during painting.
6852 ///
6853 /// {@macro flutter.widgets.IgnorePointer.semantics}
6854 ///
6855 /// Defaults to true.
6856 final bool ignoring;
6857
6858 /// Whether the semantics of this widget is ignored when compiling the
6859 /// semantics subtree.
6860 ///
6861 /// {@macro flutter.widgets.IgnorePointer.ignoringSemantics}
6862 ///
6863 /// See [SemanticsNode] for additional information about the semantics tree.
6864 @Deprecated(
6865 'Use ExcludeSemantics or create a custom ignore pointer widget instead. '
6866 'This feature was deprecated after v3.8.0-12.0.pre.'
6867 )
6868 final bool? ignoringSemantics;
6869
6870 @override
6871 RenderIgnorePointer createRenderObject(BuildContext context) {
6872 return RenderIgnorePointer(
6873 ignoring: ignoring,
6874 ignoringSemantics: ignoringSemantics,
6875 );
6876 }
6877
6878 @override
6879 void updateRenderObject(BuildContext context, RenderIgnorePointer renderObject) {
6880 renderObject
6881 ..ignoring = ignoring
6882 ..ignoringSemantics = ignoringSemantics;
6883 }
6884
6885 @override
6886 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
6887 super.debugFillProperties(properties);
6888 properties.add(DiagnosticsProperty<bool>('ignoring', ignoring));
6889 properties.add(DiagnosticsProperty<bool>('ignoringSemantics', ignoringSemantics, defaultValue: null));
6890 }
6891}
6892
6893/// A widget that absorbs pointers during hit testing.
6894///
6895/// When [absorbing] is true, this widget prevents its subtree from receiving
6896/// pointer events by terminating hit testing at itself. It still consumes space
6897/// during layout and paints its child as usual. It just prevents its children
6898/// from being the target of located events, because it returns true from
6899/// [RenderBox.hitTest].
6900///
6901/// When [ignoringSemantics] is true, the subtree will be invisible to
6902/// the semantics layer (and thus e.g. accessibility tools).
6903///
6904/// {@youtube 560 315 https://www.youtube.com/watch?v=65HoWqBboI8}
6905///
6906/// {@tool dartpad}
6907/// The following sample has an [AbsorbPointer] widget wrapping the button on
6908/// top of the stack, which absorbs pointer events, preventing its child button
6909/// __and__ the button below it in the stack from receiving the pointer events.
6910///
6911/// ** See code in examples/api/lib/widgets/basic/absorb_pointer.0.dart **
6912/// {@end-tool}
6913///
6914/// ## Semantics
6915///
6916/// Using this class may also affect how the semantics subtree underneath is
6917/// collected.
6918///
6919/// {@template flutter.widgets.AbsorbPointer.semantics}
6920/// If [absorbing] is true, pointer-related [SemanticsAction]s are removed from
6921/// the semantics subtree. Otherwise, the subtree remains untouched.
6922/// {@endtemplate}
6923///
6924/// {@template flutter.widgets.AbsorbPointer.ignoringSemantics}
6925/// The usages of [ignoringSemantics] are deprecated and not recommended. This
6926/// property was introduced to workaround the semantics behavior of the
6927/// [IgnorePointer] and its friends before v3.8.0-12.0.pre.
6928///
6929/// Before that version, entire semantics subtree is dropped if [absorbing] is
6930/// true. Developers can only use [ignoringSemantics] to preserver the semantics
6931/// subtrees.
6932///
6933/// After that version, with [absorbing] set to true, it only prevents semantics
6934/// user actions in the semantics subtree but leaves the other
6935/// [SemanticsProperties] intact. Therefore, the [ignoringSemantics] is no
6936/// longer needed.
6937///
6938/// If [ignoringSemantics] is true, the semantics subtree is dropped. Therefore,
6939/// the subtree will be invisible to assistive technologies.
6940///
6941/// If [ignoringSemantics] is false, the semantics subtree is collected as
6942/// usual.
6943/// {@endtemplate}
6944///
6945/// See also:
6946///
6947/// * [IgnorePointer], which also prevents its children from receiving pointer
6948/// events but is itself invisible to hit testing.
6949class AbsorbPointer extends SingleChildRenderObjectWidget {
6950 /// Creates a widget that absorbs pointers during hit testing.
6951 const AbsorbPointer({
6952 super.key,
6953 this.absorbing = true,
6954 @Deprecated(
6955 'Use ExcludeSemantics or create a custom absorb pointer widget instead. '
6956 'This feature was deprecated after v3.8.0-12.0.pre.'
6957 )
6958 this.ignoringSemantics,
6959 super.child,
6960 });
6961
6962 /// Whether this widget absorbs pointers during hit testing.
6963 ///
6964 /// Regardless of whether this render object absorbs pointers during hit
6965 /// testing, it will still consume space during layout and be visible during
6966 /// painting.
6967 ///
6968 /// {@macro flutter.widgets.AbsorbPointer.semantics}
6969 ///
6970 /// Defaults to true.
6971 final bool absorbing;
6972
6973 /// Whether the semantics of this render object is ignored when compiling the
6974 /// semantics tree.
6975 ///
6976 /// {@macro flutter.widgets.AbsorbPointer.ignoringSemantics}
6977 ///
6978 /// See [SemanticsNode] for additional information about the semantics tree.
6979 @Deprecated(
6980 'Use ExcludeSemantics or create a custom absorb pointer widget instead. '
6981 'This feature was deprecated after v3.8.0-12.0.pre.'
6982 )
6983 final bool? ignoringSemantics;
6984
6985 @override
6986 RenderAbsorbPointer createRenderObject(BuildContext context) {
6987 return RenderAbsorbPointer(
6988 absorbing: absorbing,
6989 ignoringSemantics: ignoringSemantics,
6990 );
6991 }
6992
6993 @override
6994 void updateRenderObject(BuildContext context, RenderAbsorbPointer renderObject) {
6995 renderObject
6996 ..absorbing = absorbing
6997 ..ignoringSemantics = ignoringSemantics;
6998 }
6999
7000 @override
7001 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
7002 super.debugFillProperties(properties);
7003 properties.add(DiagnosticsProperty<bool>('absorbing', absorbing));
7004 properties.add(DiagnosticsProperty<bool>('ignoringSemantics', ignoringSemantics, defaultValue: null));
7005 }
7006}
7007
7008/// Holds opaque meta data in the render tree.
7009///
7010/// Useful for decorating the render tree with information that will be consumed
7011/// later. For example, you could store information in the render tree that will
7012/// be used when the user interacts with the render tree but has no visual
7013/// impact prior to the interaction.
7014class MetaData extends SingleChildRenderObjectWidget {
7015 /// Creates a widget that hold opaque meta data.
7016 ///
7017 /// The [behavior] argument defaults to [HitTestBehavior.deferToChild].
7018 const MetaData({
7019 super.key,
7020 this.metaData,
7021 this.behavior = HitTestBehavior.deferToChild,
7022 super.child,
7023 });
7024
7025 /// Opaque meta data ignored by the render tree.
7026 final dynamic metaData;
7027
7028 /// How to behave during hit testing.
7029 final HitTestBehavior behavior;
7030
7031 @override
7032 RenderMetaData createRenderObject(BuildContext context) {
7033 return RenderMetaData(
7034 metaData: metaData,
7035 behavior: behavior,
7036 );
7037 }
7038
7039 @override
7040 void updateRenderObject(BuildContext context, RenderMetaData renderObject) {
7041 renderObject
7042 ..metaData = metaData
7043 ..behavior = behavior;
7044 }
7045
7046 @override
7047 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
7048 super.debugFillProperties(properties);
7049 properties.add(EnumProperty<HitTestBehavior>('behavior', behavior));
7050 properties.add(DiagnosticsProperty<dynamic>('metaData', metaData));
7051 }
7052}
7053
7054
7055// UTILITY NODES
7056
7057/// A widget that annotates the widget tree with a description of the meaning of
7058/// the widgets.
7059///
7060/// Used by assistive technologies, search engines, and other semantic analysis
7061/// software to determine the meaning of the application.
7062///
7063/// {@youtube 560 315 https://www.youtube.com/watch?v=NvtMt_DtFrQ}
7064///
7065/// See also:
7066///
7067/// * [SemanticsProperties], which contains a complete documentation for each
7068/// of the constructor parameters that belongs to semantics properties.
7069/// * [MergeSemantics], which marks a subtree as being a single node for
7070/// accessibility purposes.
7071/// * [ExcludeSemantics], which excludes a subtree from the semantics tree
7072/// (which might be useful if it is, e.g., totally decorative and not
7073/// important to the user).
7074/// * [RenderObject.describeSemanticsConfiguration], the rendering library API
7075/// through which the [Semantics] widget is actually implemented.
7076/// * [SemanticsNode], the object used by the rendering library to represent
7077/// semantics in the semantics tree.
7078/// * [SemanticsDebugger], an overlay to help visualize the semantics tree. Can
7079/// be enabled using [WidgetsApp.showSemanticsDebugger],
7080/// [MaterialApp.showSemanticsDebugger], or [CupertinoApp.showSemanticsDebugger].
7081@immutable
7082class Semantics extends SingleChildRenderObjectWidget {
7083 /// Creates a semantic annotation.
7084 ///
7085 /// To create a `const` instance of [Semantics], use the
7086 /// [Semantics.fromProperties] constructor.
7087 ///
7088 /// See also:
7089 ///
7090 /// * [SemanticsProperties], which contains a complete documentation for each
7091 /// of the constructor parameters that belongs to semantics properties.
7092 /// * [SemanticsSortKey] for a class that determines accessibility traversal
7093 /// order.
7094 Semantics({
7095 Key? key,
7096 Widget? child,
7097 bool container = false,
7098 bool explicitChildNodes = false,
7099 bool excludeSemantics = false,
7100 bool blockUserActions = false,
7101 bool? enabled,
7102 bool? checked,
7103 bool? mixed,
7104 bool? selected,
7105 bool? toggled,
7106 bool? button,
7107 bool? slider,
7108 bool? keyboardKey,
7109 bool? link,
7110 bool? header,
7111 bool? textField,
7112 bool? readOnly,
7113 bool? focusable,
7114 bool? focused,
7115 bool? inMutuallyExclusiveGroup,
7116 bool? obscured,
7117 bool? multiline,
7118 bool? scopesRoute,
7119 bool? namesRoute,
7120 bool? hidden,
7121 bool? image,
7122 bool? liveRegion,
7123 bool? expanded,
7124 int? maxValueLength,
7125 int? currentValueLength,
7126 String? identifier,
7127 String? label,
7128 AttributedString? attributedLabel,
7129 String? value,
7130 AttributedString? attributedValue,
7131 String? increasedValue,
7132 AttributedString? attributedIncreasedValue,
7133 String? decreasedValue,
7134 AttributedString? attributedDecreasedValue,
7135 String? hint,
7136 AttributedString? attributedHint,
7137 String? tooltip,
7138 String? onTapHint,
7139 String? onLongPressHint,
7140 TextDirection? textDirection,
7141 SemanticsSortKey? sortKey,
7142 SemanticsTag? tagForChildren,
7143 VoidCallback? onTap,
7144 VoidCallback? onLongPress,
7145 VoidCallback? onScrollLeft,
7146 VoidCallback? onScrollRight,
7147 VoidCallback? onScrollUp,
7148 VoidCallback? onScrollDown,
7149 VoidCallback? onIncrease,
7150 VoidCallback? onDecrease,
7151 VoidCallback? onCopy,
7152 VoidCallback? onCut,
7153 VoidCallback? onPaste,
7154 VoidCallback? onDismiss,
7155 MoveCursorHandler? onMoveCursorForwardByCharacter,
7156 MoveCursorHandler? onMoveCursorBackwardByCharacter,
7157 SetSelectionHandler? onSetSelection,
7158 SetTextHandler? onSetText,
7159 VoidCallback? onDidGainAccessibilityFocus,
7160 VoidCallback? onDidLoseAccessibilityFocus,
7161 Map<CustomSemanticsAction, VoidCallback>? customSemanticsActions,
7162 }) : this.fromProperties(
7163 key: key,
7164 child: child,
7165 container: container,
7166 explicitChildNodes: explicitChildNodes,
7167 excludeSemantics: excludeSemantics,
7168 blockUserActions: blockUserActions,
7169 properties: SemanticsProperties(
7170 enabled: enabled,
7171 checked: checked,
7172 mixed: mixed,
7173 expanded: expanded,
7174 toggled: toggled,
7175 selected: selected,
7176 button: button,
7177 slider: slider,
7178 keyboardKey: keyboardKey,
7179 link: link,
7180 header: header,
7181 textField: textField,
7182 readOnly: readOnly,
7183 focusable: focusable,
7184 focused: focused,
7185 inMutuallyExclusiveGroup: inMutuallyExclusiveGroup,
7186 obscured: obscured,
7187 multiline: multiline,
7188 scopesRoute: scopesRoute,
7189 namesRoute: namesRoute,
7190 hidden: hidden,
7191 image: image,
7192 liveRegion: liveRegion,
7193 maxValueLength: maxValueLength,
7194 currentValueLength: currentValueLength,
7195 identifier: identifier,
7196 label: label,
7197 attributedLabel: attributedLabel,
7198 value: value,
7199 attributedValue: attributedValue,
7200 increasedValue: increasedValue,
7201 attributedIncreasedValue: attributedIncreasedValue,
7202 decreasedValue: decreasedValue,
7203 attributedDecreasedValue: attributedDecreasedValue,
7204 hint: hint,
7205 attributedHint: attributedHint,
7206 tooltip: tooltip,
7207 textDirection: textDirection,
7208 sortKey: sortKey,
7209 tagForChildren: tagForChildren,
7210 onTap: onTap,
7211 onLongPress: onLongPress,
7212 onScrollLeft: onScrollLeft,
7213 onScrollRight: onScrollRight,
7214 onScrollUp: onScrollUp,
7215 onScrollDown: onScrollDown,
7216 onIncrease: onIncrease,
7217 onDecrease: onDecrease,
7218 onCopy: onCopy,
7219 onCut: onCut,
7220 onPaste: onPaste,
7221 onMoveCursorForwardByCharacter: onMoveCursorForwardByCharacter,
7222 onMoveCursorBackwardByCharacter: onMoveCursorBackwardByCharacter,
7223 onDidGainAccessibilityFocus: onDidGainAccessibilityFocus,
7224 onDidLoseAccessibilityFocus: onDidLoseAccessibilityFocus,
7225 onDismiss: onDismiss,
7226 onSetSelection: onSetSelection,
7227 onSetText: onSetText,
7228 customSemanticsActions: customSemanticsActions,
7229 hintOverrides: onTapHint != null || onLongPressHint != null ?
7230 SemanticsHintOverrides(
7231 onTapHint: onTapHint,
7232 onLongPressHint: onLongPressHint,
7233 ) : null,
7234 ),
7235 );
7236
7237 /// Creates a semantic annotation using [SemanticsProperties].
7238 const Semantics.fromProperties({
7239 super.key,
7240 super.child,
7241 this.container = false,
7242 this.explicitChildNodes = false,
7243 this.excludeSemantics = false,
7244 this.blockUserActions = false,
7245 required this.properties,
7246 });
7247
7248 /// Contains properties used by assistive technologies to make the application
7249 /// more accessible.
7250 final SemanticsProperties properties;
7251
7252 /// If [container] is true, this widget will introduce a new
7253 /// node in the semantics tree. Otherwise, the semantics will be
7254 /// merged with the semantics of any ancestors (if the ancestor allows that).
7255 ///
7256 /// Whether descendants of this widget can add their semantic information to the
7257 /// [SemanticsNode] introduced by this configuration is controlled by
7258 /// [explicitChildNodes].
7259 final bool container;
7260
7261 /// Whether descendants of this widget are allowed to add semantic information
7262 /// to the [SemanticsNode] annotated by this widget.
7263 ///
7264 /// When set to false descendants are allowed to annotate [SemanticsNode]s of
7265 /// their parent with the semantic information they want to contribute to the
7266 /// semantic tree.
7267 /// When set to true the only way for descendants to contribute semantic
7268 /// information to the semantic tree is to introduce new explicit
7269 /// [SemanticsNode]s to the tree.
7270 ///
7271 /// If the semantics properties of this node include
7272 /// [SemanticsProperties.scopesRoute] set to true, then [explicitChildNodes]
7273 /// must be true also.
7274 ///
7275 /// This setting is often used in combination with [SemanticsConfiguration.isSemanticBoundary]
7276 /// to create semantic boundaries that are either writable or not for children.
7277 final bool explicitChildNodes;
7278
7279 /// Whether to replace all child semantics with this node.
7280 ///
7281 /// Defaults to false.
7282 ///
7283 /// When this flag is set to true, all child semantics nodes are ignored.
7284 /// This can be used as a convenience for cases where a child is wrapped in
7285 /// an [ExcludeSemantics] widget and then another [Semantics] widget.
7286 final bool excludeSemantics;
7287
7288 /// Whether to block user interactions for the rendering subtree.
7289 ///
7290 /// Setting this to true will prevent users from interacting with The
7291 /// rendering object configured by this widget and its subtree through
7292 /// pointer-related [SemanticsAction]s in assistive technologies.
7293 ///
7294 /// The [SemanticsNode] created from this widget is still focusable by
7295 /// assistive technologies. Only pointer-related [SemanticsAction]s, such as
7296 /// [SemanticsAction.tap] or its friends, are blocked.
7297 ///
7298 /// If this widget is merged into a parent semantics node, only the
7299 /// [SemanticsAction]s of this widget and the widgets in the subtree are
7300 /// blocked.
7301 ///
7302 /// For example:
7303 /// ```dart
7304 /// void _myTap() { }
7305 /// void _myLongPress() { }
7306 ///
7307 /// Widget build(BuildContext context) {
7308 /// return Semantics(
7309 /// onTap: _myTap,
7310 /// child: Semantics(
7311 /// blockUserActions: true,
7312 /// onLongPress: _myLongPress,
7313 /// child: const Text('label'),
7314 /// ),
7315 /// );
7316 /// }
7317 /// ```
7318 ///
7319 /// The result semantics node will still have `_myTap`, but the `_myLongPress`
7320 /// will be blocked.
7321 final bool blockUserActions;
7322
7323 @override
7324 RenderSemanticsAnnotations createRenderObject(BuildContext context) {
7325 return RenderSemanticsAnnotations(
7326 container: container,
7327 explicitChildNodes: explicitChildNodes,
7328 excludeSemantics: excludeSemantics,
7329 blockUserActions: blockUserActions,
7330 properties: properties,
7331 textDirection: _getTextDirection(context),
7332 );
7333 }
7334
7335 TextDirection? _getTextDirection(BuildContext context) {
7336 if (properties.textDirection != null) {
7337 return properties.textDirection;
7338 }
7339
7340 final bool containsText = properties.attributedLabel != null ||
7341 properties.label != null ||
7342 properties.value != null ||
7343 properties.hint != null ||
7344 properties.tooltip != null;
7345
7346 if (!containsText) {
7347 return null;
7348 }
7349
7350 return Directionality.maybeOf(context);
7351 }
7352
7353 @override
7354 void updateRenderObject(BuildContext context, RenderSemanticsAnnotations renderObject) {
7355 renderObject
7356 ..container = container
7357 ..explicitChildNodes = explicitChildNodes
7358 ..excludeSemantics = excludeSemantics
7359 ..blockUserActions = blockUserActions
7360 ..properties = properties
7361 ..textDirection = _getTextDirection(context);
7362 }
7363
7364 @override
7365 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
7366 super.debugFillProperties(properties);
7367 properties.add(DiagnosticsProperty<bool>('container', container));
7368 properties.add(DiagnosticsProperty<SemanticsProperties>('properties', this.properties));
7369 this.properties.debugFillProperties(properties);
7370 }
7371}
7372
7373/// A widget that merges the semantics of its descendants.
7374///
7375/// Causes all the semantics of the subtree rooted at this node to be
7376/// merged into one node in the semantics tree. For example, if you
7377/// have a widget with a Text node next to a checkbox widget, this
7378/// could be used to merge the label from the Text node with the
7379/// "checked" semantic state of the checkbox into a single node that
7380/// had both the label and the checked state. Otherwise, the label
7381/// would be presented as a separate feature than the checkbox, and
7382/// the user would not be able to be sure that they were related.
7383///
7384/// {@tool snippet}
7385/// This snippet shows how to use [MergeSemantics] to merge the semantics of
7386/// a [Checkbox] and [Text] widget.
7387///
7388/// ```dart
7389/// MergeSemantics(
7390/// child: Row(
7391/// children: <Widget>[
7392/// Checkbox(
7393/// value: true,
7394/// onChanged: (bool? value) {},
7395/// ),
7396/// const Text('Settings'),
7397/// ],
7398/// ),
7399/// )
7400/// ```
7401/// {@end-tool}
7402///
7403/// Be aware that if two nodes in the subtree have conflicting
7404/// semantics, the result may be nonsensical. For example, a subtree
7405/// with a checked checkbox and an unchecked checkbox will be
7406/// presented as checked. All the labels will be merged into a single
7407/// string (with newlines separating each label from the other). If
7408/// multiple nodes in the merged subtree can handle semantic gestures,
7409/// the first one in tree order will be the one to receive the
7410/// callbacks.
7411class MergeSemantics extends SingleChildRenderObjectWidget {
7412 /// Creates a widget that merges the semantics of its descendants.
7413 const MergeSemantics({ super.key, super.child });
7414
7415 @override
7416 RenderMergeSemantics createRenderObject(BuildContext context) => RenderMergeSemantics();
7417}
7418
7419/// A widget that drops the semantics of all widget that were painted before it
7420/// in the same semantic container.
7421///
7422/// This is useful to hide widgets from accessibility tools that are painted
7423/// behind a certain widget, e.g. an alert should usually disallow interaction
7424/// with any widget located "behind" the alert (even when they are still
7425/// partially visible). Similarly, an open [Drawer] blocks interactions with
7426/// any widget outside the drawer.
7427///
7428/// See also:
7429///
7430/// * [ExcludeSemantics] which drops all semantics of its descendants.
7431class BlockSemantics extends SingleChildRenderObjectWidget {
7432 /// Creates a widget that excludes the semantics of all widgets painted before
7433 /// it in the same semantic container.
7434 const BlockSemantics({ super.key, this.blocking = true, super.child });
7435
7436 /// Whether this widget is blocking semantics of all widget that were painted
7437 /// before it in the same semantic container.
7438 final bool blocking;
7439
7440 @override
7441 RenderBlockSemantics createRenderObject(BuildContext context) => RenderBlockSemantics(blocking: blocking);
7442
7443 @override
7444 void updateRenderObject(BuildContext context, RenderBlockSemantics renderObject) {
7445 renderObject.blocking = blocking;
7446 }
7447
7448 @override
7449 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
7450 super.debugFillProperties(properties);
7451 properties.add(DiagnosticsProperty<bool>('blocking', blocking));
7452 }
7453}
7454
7455/// A widget that drops all the semantics of its descendants.
7456///
7457/// When [excluding] is true, this widget (and its subtree) is excluded from
7458/// the semantics tree.
7459///
7460/// This can be used to hide descendant widgets that would otherwise be
7461/// reported but that would only be confusing. For example, the
7462/// material library's [Chip] widget hides the avatar since it is
7463/// redundant with the chip label.
7464///
7465/// See also:
7466///
7467/// * [BlockSemantics] which drops semantics of widgets earlier in the tree.
7468class ExcludeSemantics extends SingleChildRenderObjectWidget {
7469 /// Creates a widget that drops all the semantics of its descendants.
7470 const ExcludeSemantics({
7471 super.key,
7472 this.excluding = true,
7473 super.child,
7474 });
7475
7476 /// Whether this widget is excluded in the semantics tree.
7477 final bool excluding;
7478
7479 @override
7480 RenderExcludeSemantics createRenderObject(BuildContext context) => RenderExcludeSemantics(excluding: excluding);
7481
7482 @override
7483 void updateRenderObject(BuildContext context, RenderExcludeSemantics renderObject) {
7484 renderObject.excluding = excluding;
7485 }
7486
7487 @override
7488 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
7489 super.debugFillProperties(properties);
7490 properties.add(DiagnosticsProperty<bool>('excluding', excluding));
7491 }
7492}
7493
7494/// A widget that annotates the child semantics with an index.
7495///
7496/// Semantic indexes are used by TalkBack/Voiceover to make announcements about
7497/// the current scroll state. Certain widgets like the [ListView] will
7498/// automatically provide a child index for building semantics. A user may wish
7499/// to manually provide semantic indexes if not all child of the scrollable
7500/// contribute semantics.
7501///
7502/// {@tool snippet}
7503///
7504/// The example below handles spacers in a scrollable that don't contribute
7505/// semantics. The automatic indexes would give the spaces a semantic index,
7506/// causing scroll announcements to erroneously state that there are four items
7507/// visible.
7508///
7509/// ```dart
7510/// ListView(
7511/// addSemanticIndexes: false,
7512/// semanticChildCount: 2,
7513/// children: const <Widget>[
7514/// IndexedSemantics(index: 0, child: Text('First')),
7515/// Spacer(),
7516/// IndexedSemantics(index: 1, child: Text('Second')),
7517/// Spacer(),
7518/// ],
7519/// )
7520/// ```
7521/// {@end-tool}
7522///
7523/// See also:
7524///
7525/// * [CustomScrollView], for an explanation of index semantics.
7526class IndexedSemantics extends SingleChildRenderObjectWidget {
7527 /// Creates a widget that annotated the first child semantics node with an index.
7528 const IndexedSemantics({
7529 super.key,
7530 required this.index,
7531 super.child,
7532 });
7533
7534 /// The index used to annotate the first child semantics node.
7535 final int index;
7536
7537 @override
7538 RenderIndexedSemantics createRenderObject(BuildContext context) => RenderIndexedSemantics(index: index);
7539
7540 @override
7541 void updateRenderObject(BuildContext context, RenderIndexedSemantics renderObject) {
7542 renderObject.index = index;
7543 }
7544 @override
7545 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
7546 super.debugFillProperties(properties);
7547 properties.add(DiagnosticsProperty<int>('index', index));
7548 }
7549}
7550
7551/// A widget that builds its child.
7552///
7553/// Useful for attaching a key to an existing widget.
7554class KeyedSubtree extends StatelessWidget {
7555 /// Creates a widget that builds its child.
7556 const KeyedSubtree({
7557 super.key,
7558 required this.child,
7559 });
7560
7561 /// Creates a KeyedSubtree for child with a key that's based on the child's existing key or childIndex.
7562 factory KeyedSubtree.wrap(Widget child, int childIndex) {
7563 final Key key = child.key != null ? ValueKey<Key>(child.key!) : ValueKey<int>(childIndex);
7564 return KeyedSubtree(key: key, child: child);
7565 }
7566
7567 /// The widget below this widget in the tree.
7568 ///
7569 /// {@macro flutter.widgets.ProxyWidget.child}
7570 final Widget child;
7571
7572 /// Wrap each item in a KeyedSubtree whose key is based on the item's existing key or
7573 /// the sum of its list index and `baseIndex`.
7574 static List<Widget> ensureUniqueKeysForList(List<Widget> items, { int baseIndex = 0 }) {
7575 if (items.isEmpty) {
7576 return items;
7577 }
7578
7579 final List<Widget> itemsWithUniqueKeys = <Widget>[];
7580 int itemIndex = baseIndex;
7581 for (final Widget item in items) {
7582 itemsWithUniqueKeys.add(KeyedSubtree.wrap(item, itemIndex));
7583 itemIndex += 1;
7584 }
7585
7586 assert(!debugItemsHaveDuplicateKeys(itemsWithUniqueKeys));
7587 return itemsWithUniqueKeys;
7588 }
7589
7590 @override
7591 Widget build(BuildContext context) => child;
7592}
7593
7594/// A stateless utility widget whose [build] method uses its
7595/// [builder] callback to create the widget's child.
7596///
7597/// {@youtube 560 315 https://www.youtube.com/watch?v=xXNOkIuSYuA}
7598///
7599/// This widget is an inline alternative to defining a [StatelessWidget]
7600/// subclass. For example, instead of defining a widget as follows:
7601///
7602/// ```dart
7603/// class Foo extends StatelessWidget {
7604/// const Foo({super.key});
7605/// @override
7606/// Widget build(BuildContext context) => const Text('foo');
7607/// }
7608/// ```
7609///
7610/// ...and using it in the usual way:
7611///
7612/// ```dart
7613/// // continuing from previous example...
7614/// const Center(child: Foo())
7615/// ```
7616///
7617/// ...one could instead define and use it in a single step, without
7618/// defining a new widget class:
7619///
7620/// ```dart
7621/// Center(
7622/// child: Builder(
7623/// builder: (BuildContext context) => const Text('foo'),
7624/// ),
7625/// )
7626/// ```
7627///
7628/// The difference between either of the previous examples and
7629/// creating a child directly without an intervening widget, is the
7630/// extra [BuildContext] element that the additional widget adds. This
7631/// is particularly noticeable when the tree contains an inherited
7632/// widget that is referred to by a method like [Scaffold.of],
7633/// which visits the child widget's BuildContext ancestors.
7634///
7635/// In the following example the button's `onPressed` callback is unable
7636/// to find the enclosing [ScaffoldState] with [Scaffold.of]:
7637///
7638/// ```dart
7639/// Widget build(BuildContext context) {
7640/// return Scaffold(
7641/// body: Center(
7642/// child: TextButton(
7643/// onPressed: () {
7644/// // Fails because Scaffold.of() doesn't find anything
7645/// // above this widget's context.
7646/// print(Scaffold.of(context).hasAppBar);
7647/// },
7648/// child: const Text('hasAppBar'),
7649/// )
7650/// ),
7651/// );
7652/// }
7653/// ```
7654///
7655/// A [Builder] widget introduces an additional [BuildContext] element
7656/// and so the [Scaffold.of] method succeeds.
7657///
7658/// ```dart
7659/// Widget build(BuildContext context) {
7660/// return Scaffold(
7661/// body: Builder(
7662/// builder: (BuildContext context) {
7663/// return Center(
7664/// child: TextButton(
7665/// onPressed: () {
7666/// print(Scaffold.of(context).hasAppBar);
7667/// },
7668/// child: const Text('hasAppBar'),
7669/// ),
7670/// );
7671/// },
7672/// ),
7673/// );
7674/// }
7675/// ```
7676///
7677/// See also:
7678///
7679/// * [StatefulBuilder], A stateful utility widget whose [build] method uses its
7680/// [builder] callback to create the widget's child.
7681class Builder extends StatelessWidget {
7682 /// Creates a widget that delegates its build to a callback.
7683 const Builder({
7684 super.key,
7685 required this.builder,
7686 });
7687
7688 /// Called to obtain the child widget.
7689 ///
7690 /// This function is called whenever this widget is included in its parent's
7691 /// build and the old widget (if any) that it synchronizes with has a distinct
7692 /// object identity. Typically the parent's build method will construct
7693 /// a new tree of widgets and so a new Builder child will not be [identical]
7694 /// to the corresponding old one.
7695 final WidgetBuilder builder;
7696
7697 @override
7698 Widget build(BuildContext context) => builder(context);
7699}
7700
7701/// Signature for the builder callback used by [StatefulBuilder].
7702///
7703/// Call `setState` to schedule the [StatefulBuilder] to rebuild.
7704typedef StatefulWidgetBuilder = Widget Function(BuildContext context, StateSetter setState);
7705
7706/// A platonic widget that both has state and calls a closure to obtain its child widget.
7707///
7708/// {@youtube 560 315 https://www.youtube.com/watch?v=syvT63CosNE}
7709///
7710/// The [StateSetter] function passed to the [builder] is used to invoke a
7711/// rebuild instead of a typical [State]'s [State.setState].
7712///
7713/// Since the [builder] is re-invoked when the [StateSetter] is called, any
7714/// variables that represents state should be kept outside the [builder] function.
7715///
7716/// {@tool snippet}
7717///
7718/// This example shows using an inline StatefulBuilder that rebuilds and that
7719/// also has state.
7720///
7721/// ```dart
7722/// await showDialog<void>(
7723/// context: context,
7724/// builder: (BuildContext context) {
7725/// int? selectedRadio = 0;
7726/// return AlertDialog(
7727/// content: StatefulBuilder(
7728/// builder: (BuildContext context, StateSetter setState) {
7729/// return Column(
7730/// mainAxisSize: MainAxisSize.min,
7731/// children: List<Widget>.generate(4, (int index) {
7732/// return Radio<int>(
7733/// value: index,
7734/// groupValue: selectedRadio,
7735/// onChanged: (int? value) {
7736/// setState(() => selectedRadio = value);
7737/// },
7738/// );
7739/// }),
7740/// );
7741/// },
7742/// ),
7743/// );
7744/// },
7745/// );
7746/// ```
7747/// {@end-tool}
7748///
7749/// See also:
7750///
7751/// * [Builder], the platonic stateless widget.
7752class StatefulBuilder extends StatefulWidget {
7753 /// Creates a widget that both has state and delegates its build to a callback.
7754 const StatefulBuilder({
7755 super.key,
7756 required this.builder,
7757 });
7758
7759 /// Called to obtain the child widget.
7760 ///
7761 /// This function is called whenever this widget is included in its parent's
7762 /// build and the old widget (if any) that it synchronizes with has a distinct
7763 /// object identity. Typically the parent's build method will construct
7764 /// a new tree of widgets and so a new Builder child will not be [identical]
7765 /// to the corresponding old one.
7766 final StatefulWidgetBuilder builder;
7767
7768 @override
7769 State<StatefulBuilder> createState() => _StatefulBuilderState();
7770}
7771
7772class _StatefulBuilderState extends State<StatefulBuilder> {
7773 @override
7774 Widget build(BuildContext context) => widget.builder(context, setState);
7775}
7776
7777/// A widget that paints its area with a specified [Color] and then draws its
7778/// child on top of that color.
7779class ColoredBox extends SingleChildRenderObjectWidget {
7780 /// Creates a widget that paints its area with the specified [Color].
7781 const ColoredBox({ required this.color, super.child, super.key });
7782
7783 /// The color to paint the background area with.
7784 final Color color;
7785
7786 @override
7787 RenderObject createRenderObject(BuildContext context) {
7788 return _RenderColoredBox(color: color);
7789 }
7790
7791 @override
7792 void updateRenderObject(BuildContext context, RenderObject renderObject) {
7793 (renderObject as _RenderColoredBox).color = color;
7794 }
7795
7796 @override
7797 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
7798 super.debugFillProperties(properties);
7799 properties.add(DiagnosticsProperty<Color>('color', color));
7800 }
7801}
7802
7803class _RenderColoredBox extends RenderProxyBoxWithHitTestBehavior {
7804 _RenderColoredBox({ required Color color })
7805 : _color = color,
7806 super(behavior: HitTestBehavior.opaque);
7807
7808 /// The fill color for this render object.
7809 Color get color => _color;
7810 Color _color;
7811 set color(Color value) {
7812 if (value == _color) {
7813 return;
7814 }
7815 _color = value;
7816 markNeedsPaint();
7817 }
7818
7819 @override
7820 void paint(PaintingContext context, Offset offset) {
7821 // It's tempting to want to optimize out this `drawRect()` call if the
7822 // color is transparent (alpha==0), but doing so would be incorrect. See
7823 // https://github.com/flutter/flutter/pull/72526#issuecomment-749185938 for
7824 // a good description of why.
7825 if (size > Size.zero) {
7826 context.canvas.drawRect(offset & size, Paint()..color = color);
7827 }
7828 if (child != null) {
7829 context.paintChild(child!, offset);
7830 }
7831 }
7832}
7833