| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:math' as math; |
| import 'dart:ui' as ui show Image, ImageFilter, TextHeightBehavior; |
| |
| import 'package:flutter/animation.dart'; |
| import 'package:flutter/foundation.dart'; |
| import 'package:flutter/gestures.dart'; |
| import 'package:flutter/rendering.dart'; |
| import 'package:flutter/services.dart'; |
| |
| import 'binding.dart'; |
| import 'debug.dart'; |
| import 'framework.dart'; |
| import 'localizations.dart'; |
| import 'widget_span.dart'; |
| |
| export 'package:flutter/animation.dart'; |
| export 'package:flutter/foundation.dart' show |
| ChangeNotifier, |
| FlutterErrorDetails, |
| Listenable, |
| TargetPlatform, |
| ValueNotifier; |
| export 'package:flutter/painting.dart'; |
| export 'package:flutter/rendering.dart' show |
| AlignmentGeometryTween, |
| AlignmentTween, |
| Axis, |
| BoxConstraints, |
| BoxConstraintsTransform, |
| CrossAxisAlignment, |
| CustomClipper, |
| CustomPainter, |
| CustomPainterSemantics, |
| DecorationPosition, |
| FlexFit, |
| FlowDelegate, |
| FlowPaintingContext, |
| FractionalOffsetTween, |
| HitTestBehavior, |
| LayerLink, |
| MainAxisAlignment, |
| MainAxisSize, |
| MouseCursor, |
| MultiChildLayoutDelegate, |
| PaintingContext, |
| PointerCancelEvent, |
| PointerCancelEventListener, |
| PointerDownEvent, |
| PointerDownEventListener, |
| PointerEvent, |
| PointerMoveEvent, |
| PointerMoveEventListener, |
| PointerUpEvent, |
| PointerUpEventListener, |
| RelativeRect, |
| SemanticsBuilderCallback, |
| ShaderCallback, |
| ShapeBorderClipper, |
| SingleChildLayoutDelegate, |
| StackFit, |
| SystemMouseCursors, |
| TextOverflow, |
| ValueChanged, |
| ValueGetter, |
| WrapAlignment, |
| WrapCrossAlignment; |
| export 'package:flutter/services.dart' show |
| AssetBundle; |
| |
| // Examples can assume: |
| // class TestWidget extends StatelessWidget { const TestWidget({super.key}); @override Widget build(BuildContext context) => const Placeholder(); } |
| // late WidgetTester tester; |
| // late bool _visible; |
| // class Sky extends CustomPainter { @override void paint(Canvas c, Size s) {} @override bool shouldRepaint(Sky s) => false; } |
| // late BuildContext context; |
| // String userAvatarUrl = ''; |
| |
| // BIDIRECTIONAL TEXT SUPPORT |
| |
| /// An [InheritedElement] that has hundreds of dependencies but will |
| /// infrequently change. This provides a performance tradeoff where building |
| /// the [Widget]s is faster but performing updates is slower. |
| /// |
| /// | | _UbiquitousInheritedElement | InheritedElement | |
| /// |---------------------|------------------------------|------------------| |
| /// | insert (best case) | O(1) | O(1) | |
| /// | insert (worst case) | O(1) | O(n) | |
| /// | search (best case) | O(n) | O(1) | |
| /// | search (worst case) | O(n) | O(n) | |
| /// |
| /// Insert happens when building the [Widget] tree, search happens when updating |
| /// [Widget]s. |
| class _UbiquitousInheritedElement extends InheritedElement { |
| /// Creates an element that uses the given widget as its configuration. |
| _UbiquitousInheritedElement(super.widget); |
| |
| @override |
| void setDependencies(Element dependent, Object? value) { |
| // This is where the cost of [InheritedElement] is incurred during build |
| // time of the widget tree. Omitting this bookkeeping is where the |
| // performance savings come from. |
| assert(value == null); |
| } |
| |
| @override |
| Object? getDependencies(Element dependent) { |
| return null; |
| } |
| |
| @override |
| void notifyClients(InheritedWidget oldWidget) { |
| _recurseChildren(this, (Element element) { |
| if (element.doesDependOnInheritedElement(this)) { |
| notifyDependent(oldWidget, element); |
| } |
| }); |
| } |
| |
| static void _recurseChildren(Element element, ElementVisitor visitor) { |
| element.visitChildren((Element child) { |
| _recurseChildren(child, visitor); |
| }); |
| visitor(element); |
| } |
| } |
| |
| /// See also: |
| /// |
| /// * [_UbiquitousInheritedElement], the [Element] for [_UbiquitousInheritedWidget]. |
| abstract class _UbiquitousInheritedWidget extends InheritedWidget { |
| const _UbiquitousInheritedWidget({super.key, required super.child}); |
| |
| @override |
| InheritedElement createElement() => _UbiquitousInheritedElement(this); |
| } |
| |
| /// A widget that determines the ambient directionality of text and |
| /// text-direction-sensitive render objects. |
| /// |
| /// For example, [Padding] depends on the [Directionality] to resolve |
| /// [EdgeInsetsDirectional] objects into absolute [EdgeInsets] objects. |
| class Directionality extends _UbiquitousInheritedWidget { |
| /// Creates a widget that determines the directionality of text and |
| /// text-direction-sensitive render objects. |
| /// |
| /// The [textDirection] and [child] arguments must not be null. |
| const Directionality({ |
| super.key, |
| required this.textDirection, |
| required super.child, |
| }); |
| |
| /// The text direction for this subtree. |
| final TextDirection textDirection; |
| |
| /// The text direction from the closest instance of this class that encloses |
| /// the given context. |
| /// |
| /// If there is no [Directionality] ancestor widget in the tree at the given |
| /// context, then this will throw a descriptive [FlutterError] in debug mode |
| /// and an exception in release mode. |
| /// |
| /// Typical usage is as follows: |
| /// |
| /// ```dart |
| /// TextDirection textDirection = Directionality.of(context); |
| /// ``` |
| /// |
| /// See also: |
| /// |
| /// * [maybeOf], which will return null if no [Directionality] ancestor |
| /// widget is in the tree. |
| static TextDirection of(BuildContext context) { |
| assert(debugCheckHasDirectionality(context)); |
| final Directionality widget = context.dependOnInheritedWidgetOfExactType<Directionality>()!; |
| return widget.textDirection; |
| } |
| |
| /// The text direction from the closest instance of this class that encloses |
| /// the given context. |
| /// |
| /// If there is no [Directionality] ancestor widget in the tree at the given |
| /// context, then this will return null. |
| /// |
| /// Typical usage is as follows: |
| /// |
| /// ```dart |
| /// TextDirection? textDirection = Directionality.maybeOf(context); |
| /// ``` |
| /// |
| /// See also: |
| /// |
| /// * [of], which will throw if no [Directionality] ancestor widget is in the |
| /// tree. |
| static TextDirection? maybeOf(BuildContext context) { |
| final Directionality? widget = context.dependOnInheritedWidgetOfExactType<Directionality>(); |
| return widget?.textDirection; |
| } |
| |
| @override |
| bool updateShouldNotify(Directionality oldWidget) => textDirection != oldWidget.textDirection; |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(EnumProperty<TextDirection>('textDirection', textDirection)); |
| } |
| } |
| |
| |
| // PAINTING NODES |
| |
| /// A widget that makes its child partially transparent. |
| /// |
| /// This class paints its child into an intermediate buffer and then blends the |
| /// child back into the scene partially transparent. |
| /// |
| /// For values of opacity other than 0.0 and 1.0, this class is relatively |
| /// expensive because it requires painting the child into an intermediate |
| /// buffer. For the value 0.0, the child is not painted at all. For the |
| /// value 1.0, the child is painted immediately without an intermediate buffer. |
| /// |
| /// The presence of the intermediate buffer which has a transparent background |
| /// by default may cause some child widgets to behave differently. For example |
| /// a [BackdropFilter] child will only be able to apply its filter to the content |
| /// between this widget and the backdrop child and may require adjusting the |
| /// [BackdropFilter.blendMode] property to produce the desired results. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=9hltevOHQBw} |
| /// |
| /// {@tool snippet} |
| /// |
| /// This example shows some [Text] when the `_visible` member field is true, and |
| /// hides it when it is false: |
| /// |
| /// ```dart |
| /// Opacity( |
| /// opacity: _visible ? 1.0 : 0.0, |
| /// child: const Text("Now you see me, now you don't!"), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// This is more efficient than adding and removing the child widget from the |
| /// tree on demand. |
| /// |
| /// ## Performance considerations for opacity animation |
| /// |
| /// Animating an [Opacity] widget directly causes the widget (and possibly its |
| /// subtree) to rebuild each frame, which is not very efficient. Consider using |
| /// an [AnimatedOpacity] or a [FadeTransition] instead. |
| /// |
| /// ## Transparent image |
| /// |
| /// If only a single [Image] or [Color] needs to be composited with an opacity |
| /// between 0.0 and 1.0, it's much faster to directly use them without [Opacity] |
| /// widgets. |
| /// |
| /// For example, `Container(color: Color.fromRGBO(255, 0, 0, 0.5))` is much |
| /// faster than `Opacity(opacity: 0.5, child: Container(color: Colors.red))`. |
| /// |
| /// {@tool snippet} |
| /// |
| /// The following example draws an [Image] with 0.5 opacity without using |
| /// [Opacity]: |
| /// |
| /// ```dart |
| /// Image.network( |
| /// 'https://raw.githubusercontent.com/flutter/assets-for-api-docs/master/packages/diagrams/assets/blend_mode_destination.jpeg', |
| /// color: const Color.fromRGBO(255, 255, 255, 0.5), |
| /// colorBlendMode: BlendMode.modulate |
| /// ) |
| /// ``` |
| /// |
| /// {@end-tool} |
| /// |
| /// Directly drawing an [Image] or [Color] with opacity is faster than using |
| /// [Opacity] on top of them because [Opacity] could apply the opacity to a |
| /// group of widgets and therefore a costly offscreen buffer will be used. |
| /// Drawing content into the offscreen buffer may also trigger render target |
| /// switches and such switching is particularly slow in older GPUs. |
| /// |
| /// See also: |
| /// |
| /// * [Visibility], which can hide a child more efficiently (albeit less |
| /// subtly, because it is either visible or hidden, rather than allowing |
| /// fractional opacity values). Specifically, the [Visibility.maintain] |
| /// constructor is equivalent to using an opacity widget with values of |
| /// `0.0` or `1.0`. |
| /// * [ShaderMask], which can apply more elaborate effects to its child. |
| /// * [Transform], which applies an arbitrary transform to its child widget at |
| /// paint time. |
| /// * [AnimatedOpacity], which uses an animation internally to efficiently |
| /// animate opacity. |
| /// * [FadeTransition], which uses a provided animation to efficiently animate |
| /// opacity. |
| /// * [Image], which can directly provide a partially transparent image with |
| /// much less performance hit. |
| class Opacity extends SingleChildRenderObjectWidget { |
| /// Creates a widget that makes its child partially transparent. |
| /// |
| /// The [opacity] argument must not be null and must be between 0.0 and 1.0 |
| /// (inclusive). |
| const Opacity({ |
| super.key, |
| required this.opacity, |
| this.alwaysIncludeSemantics = false, |
| super.child, |
| }) : assert(opacity >= 0.0 && opacity <= 1.0); |
| |
| /// The fraction to scale the child's alpha value. |
| /// |
| /// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent |
| /// (i.e., invisible). |
| /// |
| /// The opacity must not be null. |
| /// |
| /// Values 1.0 and 0.0 are painted with a fast path. Other values |
| /// require painting the child into an intermediate buffer, which is |
| /// expensive. |
| final double opacity; |
| |
| /// Whether the semantic information of the children is always included. |
| /// |
| /// Defaults to false. |
| /// |
| /// When true, regardless of the opacity settings the child semantic |
| /// information is exposed as if the widget were fully visible. This is |
| /// useful in cases where labels may be hidden during animations that |
| /// would otherwise contribute relevant semantics. |
| final bool alwaysIncludeSemantics; |
| |
| @override |
| RenderOpacity createRenderObject(BuildContext context) { |
| return RenderOpacity( |
| opacity: opacity, |
| alwaysIncludeSemantics: alwaysIncludeSemantics, |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderOpacity renderObject) { |
| renderObject |
| ..opacity = opacity |
| ..alwaysIncludeSemantics = alwaysIncludeSemantics; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DoubleProperty('opacity', opacity)); |
| properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics')); |
| } |
| } |
| |
| /// A widget that applies a mask generated by a [Shader] to its child. |
| /// |
| /// For example, [ShaderMask] can be used to gradually fade out the edge |
| /// of a child by using a [ui.Gradient.linear] mask. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=7sUL66pTQ7Q} |
| /// |
| /// {@tool snippet} |
| /// |
| /// This example makes the text look like it is on fire: |
| /// |
| /// ```dart |
| /// ShaderMask( |
| /// shaderCallback: (Rect bounds) { |
| /// return RadialGradient( |
| /// center: Alignment.topLeft, |
| /// radius: 1.0, |
| /// colors: <Color>[Colors.yellow, Colors.deepOrange.shade900], |
| /// tileMode: TileMode.mirror, |
| /// ).createShader(bounds); |
| /// }, |
| /// child: const Text('I’m burning the memories'), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [Opacity], which can apply a uniform alpha effect to its child. |
| /// * [CustomPaint], which lets you draw directly on the canvas. |
| /// * [DecoratedBox], for another approach at decorating child widgets. |
| /// * [BackdropFilter], which applies an image filter to the background. |
| class ShaderMask extends SingleChildRenderObjectWidget { |
| /// Creates a widget that applies a mask generated by a [Shader] to its child. |
| /// |
| /// The [shaderCallback] and [blendMode] arguments must not be null. |
| const ShaderMask({ |
| super.key, |
| required this.shaderCallback, |
| this.blendMode = BlendMode.modulate, |
| super.child, |
| }); |
| |
| /// Called to create the [dart:ui.Shader] that generates the mask. |
| /// |
| /// The shader callback is called with the current size of the child so that |
| /// it can customize the shader to the size and location of the child. |
| /// |
| /// Typically this will use a [LinearGradient], [RadialGradient], or |
| /// [SweepGradient] to create the [dart:ui.Shader], though the |
| /// [dart:ui.ImageShader] class could also be used. |
| final ShaderCallback shaderCallback; |
| |
| /// The [BlendMode] to use when applying the shader to the child. |
| /// |
| /// The default, [BlendMode.modulate], is useful for applying an alpha blend |
| /// to the child. Other blend modes can be used to create other effects. |
| final BlendMode blendMode; |
| |
| @override |
| RenderShaderMask createRenderObject(BuildContext context) { |
| return RenderShaderMask( |
| shaderCallback: shaderCallback, |
| blendMode: blendMode, |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderShaderMask renderObject) { |
| renderObject |
| ..shaderCallback = shaderCallback |
| ..blendMode = blendMode; |
| } |
| } |
| |
| /// A widget that applies a filter to the existing painted content and then |
| /// paints [child]. |
| /// |
| /// The filter will be applied to all the area within its parent or ancestor |
| /// widget's clip. If there's no clip, the filter will be applied to the full |
| /// screen. |
| /// |
| /// The results of the filter will be blended back into the background using |
| /// the [blendMode] parameter. |
| /// {@template flutter.widgets.BackdropFilter.blendMode} |
| /// The only value for [blendMode] that is supported on all platforms is |
| /// [BlendMode.srcOver] which works well for most scenes. But that value may |
| /// produce surprising results when a parent of the [BackdropFilter] uses a |
| /// temporary buffer, or save layer, as does an [Opacity] widget. In that |
| /// situation, a value of [BlendMode.src] can produce more pleasing results, |
| /// but at the cost of incompatibility with some platforms, most notably the |
| /// html renderer for web applications. |
| /// {@endtemplate} |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=dYRs7Q1vfYI} |
| /// |
| /// {@tool snippet} |
| /// If the [BackdropFilter] needs to be applied to an area that exactly matches |
| /// its child, wraps the [BackdropFilter] with a clip widget that clips exactly |
| /// to that child. |
| /// |
| /// ```dart |
| /// Stack( |
| /// fit: StackFit.expand, |
| /// children: <Widget>[ |
| /// Text('0' * 10000), |
| /// Center( |
| /// child: ClipRect( // <-- clips to the 200x200 [Container] below |
| /// child: BackdropFilter( |
| /// filter: ui.ImageFilter.blur( |
| /// sigmaX: 5.0, |
| /// sigmaY: 5.0, |
| /// ), |
| /// child: Container( |
| /// alignment: Alignment.center, |
| /// width: 200.0, |
| /// height: 200.0, |
| /// child: const Text('Hello World'), |
| /// ), |
| /// ), |
| /// ), |
| /// ), |
| /// ], |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// This effect is relatively expensive, especially if the filter is non-local, |
| /// such as a blur. |
| /// |
| /// If all you want to do is apply an [ImageFilter] to a single widget |
| /// (as opposed to applying the filter to everything _beneath_ a widget), use |
| /// [ImageFiltered] instead. For that scenario, [ImageFiltered] is both |
| /// easier to use and less expensive than [BackdropFilter]. |
| /// |
| /// {@tool snippet} |
| /// |
| /// This example shows how the common case of applying a [BackdropFilter] blur |
| /// to a single sibling can be replaced with an [ImageFiltered] widget. This code |
| /// is generally simpler and the performance will be improved dramatically for |
| /// complex filters like blurs. |
| /// |
| /// The implementation below is unnecessarily expensive. |
| /// |
| /// ```dart |
| /// Widget buildBackdrop() { |
| /// return Stack( |
| /// children: <Widget>[ |
| /// Positioned.fill(child: Image.asset('image.png')), |
| /// Positioned.fill( |
| /// child: BackdropFilter( |
| /// filter: ui.ImageFilter.blur(sigmaX: 6, sigmaY: 6), |
| /// ), |
| /// ), |
| /// ], |
| /// ); |
| /// } |
| /// ``` |
| /// {@end-tool} |
| /// {@tool snippet} |
| /// Instead consider the following approach which directly applies a blur |
| /// to the child widget. |
| /// |
| /// ```dart |
| /// Widget buildFilter() { |
| /// return ImageFiltered( |
| /// imageFilter: ui.ImageFilter.blur(sigmaX: 6, sigmaY: 6), |
| /// child: Image.asset('image.png'), |
| /// ); |
| /// } |
| /// ``` |
| /// |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [ImageFiltered], which applies an [ImageFilter] to its child. |
| /// * [DecoratedBox], which draws a background under (or over) a widget. |
| /// * [Opacity], which changes the opacity of the widget itself. |
| /// * https://flutter.dev/go/ios-platformview-backdrop-filter-blur for details and restrictions when an iOS PlatformView needs to be blurred. |
| class BackdropFilter extends SingleChildRenderObjectWidget { |
| /// Creates a backdrop filter. |
| /// |
| /// The [filter] argument must not be null. |
| /// The [blendMode] argument will default to [BlendMode.srcOver] and must not be |
| /// null if provided. |
| const BackdropFilter({ |
| super.key, |
| required this.filter, |
| super.child, |
| this.blendMode = BlendMode.srcOver, |
| }); |
| |
| /// The image filter to apply to the existing painted content before painting the child. |
| /// |
| /// For example, consider using [ImageFilter.blur] to create a backdrop |
| /// blur effect. |
| final ui.ImageFilter filter; |
| |
| /// The blend mode to use to apply the filtered background content onto the background |
| /// surface. |
| /// |
| /// {@macro flutter.widgets.BackdropFilter.blendMode} |
| final BlendMode blendMode; |
| |
| @override |
| RenderBackdropFilter createRenderObject(BuildContext context) { |
| return RenderBackdropFilter(filter: filter, blendMode: blendMode); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderBackdropFilter renderObject) { |
| renderObject |
| ..filter = filter |
| ..blendMode = blendMode; |
| } |
| } |
| |
| /// A widget that provides a canvas on which to draw during the paint phase. |
| /// |
| /// When asked to paint, [CustomPaint] first asks its [painter] to paint on the |
| /// current canvas, then it paints its child, and then, after painting its |
| /// child, it asks its [foregroundPainter] to paint. The coordinate system of the |
| /// canvas matches the coordinate system of the [CustomPaint] object. The |
| /// painters are expected to paint within a rectangle starting at the origin and |
| /// encompassing a region of the given size. (If the painters paint outside |
| /// those bounds, there might be insufficient memory allocated to rasterize the |
| /// painting commands and the resulting behavior is undefined.) To enforce |
| /// painting within those bounds, consider wrapping this [CustomPaint] with a |
| /// [ClipRect] widget. |
| /// |
| /// Painters are implemented by subclassing [CustomPainter]. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=kp14Y4uHpHs} |
| /// |
| /// Because custom paint calls its painters during paint, you cannot call |
| /// `setState` or `markNeedsLayout` during the callback (the layout for this |
| /// frame has already happened). |
| /// |
| /// Custom painters normally size themselves to their child. If they do not have |
| /// a child, they attempt to size themselves to the [size], which defaults to |
| /// [Size.zero]. [size] must not be null. |
| /// |
| /// [isComplex] and [willChange] are hints to the compositor's raster cache |
| /// and must not be null. |
| /// |
| /// {@tool snippet} |
| /// |
| /// This example shows how the sample custom painter shown at [CustomPainter] |
| /// could be used in a [CustomPaint] widget to display a background to some |
| /// text. |
| /// |
| /// ```dart |
| /// CustomPaint( |
| /// painter: Sky(), |
| /// child: const Center( |
| /// child: Text( |
| /// 'Once upon a time...', |
| /// style: TextStyle( |
| /// fontSize: 40.0, |
| /// fontWeight: FontWeight.w900, |
| /// color: Color(0xFFFFFFFF), |
| /// ), |
| /// ), |
| /// ), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [CustomPainter], the class to extend when creating custom painters. |
| /// * [Canvas], the class that a custom painter uses to paint. |
| class CustomPaint extends SingleChildRenderObjectWidget { |
| /// Creates a widget that delegates its painting. |
| const CustomPaint({ |
| super.key, |
| this.painter, |
| this.foregroundPainter, |
| this.size = Size.zero, |
| this.isComplex = false, |
| this.willChange = false, |
| super.child, |
| }) : assert(painter != null || foregroundPainter != null || (!isComplex && !willChange)); |
| |
| /// The painter that paints before the children. |
| final CustomPainter? painter; |
| |
| /// The painter that paints after the children. |
| final CustomPainter? foregroundPainter; |
| |
| /// The size that this [CustomPaint] should aim for, given the layout |
| /// constraints, if there is no child. |
| /// |
| /// Defaults to [Size.zero]. |
| /// |
| /// If there's a child, this is ignored, and the size of the child is used |
| /// instead. |
| final Size size; |
| |
| /// Whether the painting is complex enough to benefit from caching. |
| /// |
| /// The compositor contains a raster cache that holds bitmaps of layers in |
| /// order to avoid the cost of repeatedly rendering those layers on each |
| /// frame. If this flag is not set, then the compositor will apply its own |
| /// heuristics to decide whether the this layer is complex enough to benefit |
| /// from caching. |
| /// |
| /// This flag can't be set to true if both [painter] and [foregroundPainter] |
| /// are null because this flag will be ignored in such case. |
| final bool isComplex; |
| |
| /// Whether the raster cache should be told that this painting is likely |
| /// to change in the next frame. |
| /// |
| /// This flag can't be set to true if both [painter] and [foregroundPainter] |
| /// are null because this flag will be ignored in such case. |
| final bool willChange; |
| |
| @override |
| RenderCustomPaint createRenderObject(BuildContext context) { |
| return RenderCustomPaint( |
| painter: painter, |
| foregroundPainter: foregroundPainter, |
| preferredSize: size, |
| isComplex: isComplex, |
| willChange: willChange, |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderCustomPaint renderObject) { |
| renderObject |
| ..painter = painter |
| ..foregroundPainter = foregroundPainter |
| ..preferredSize = size |
| ..isComplex = isComplex |
| ..willChange = willChange; |
| } |
| |
| @override |
| void didUnmountRenderObject(RenderCustomPaint renderObject) { |
| renderObject |
| ..painter = null |
| ..foregroundPainter = null; |
| } |
| } |
| |
| /// A widget that clips its child using a rectangle. |
| /// |
| /// By default, [ClipRect] prevents its child from painting outside its |
| /// bounds, but the size and location of the clip rect can be customized using a |
| /// custom [clipper]. |
| /// |
| /// [ClipRect] is commonly used with these widgets, which commonly paint outside |
| /// their bounds: |
| /// |
| /// * [CustomPaint] |
| /// * [CustomSingleChildLayout] |
| /// * [CustomMultiChildLayout] |
| /// * [Align] and [Center] (e.g., if [Align.widthFactor] or |
| /// [Align.heightFactor] is less than 1.0). |
| /// * [OverflowBox] |
| /// * [SizedOverflowBox] |
| /// |
| /// {@tool snippet} |
| /// |
| /// For example, by combining a [ClipRect] with an [Align], one can show just |
| /// the top half of an [Image]: |
| /// |
| /// ```dart |
| /// ClipRect( |
| /// child: Align( |
| /// alignment: Alignment.topCenter, |
| /// heightFactor: 0.5, |
| /// child: Image.network(userAvatarUrl), |
| /// ), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [CustomClipper], for information about creating custom clips. |
| /// * [ClipRRect], for a clip with rounded corners. |
| /// * [ClipOval], for an elliptical clip. |
| /// * [ClipPath], for an arbitrarily shaped clip. |
| class ClipRect extends SingleChildRenderObjectWidget { |
| /// Creates a rectangular clip. |
| /// |
| /// If [clipper] is null, the clip will match the layout size and position of |
| /// the child. |
| /// |
| /// The [clipBehavior] argument must not be null. If [clipBehavior] is |
| /// [Clip.none], no clipping will be applied. |
| const ClipRect({ |
| super.key, |
| this.clipper, |
| this.clipBehavior = Clip.hardEdge, |
| super.child, |
| }); |
| |
| /// If non-null, determines which clip to use. |
| final CustomClipper<Rect>? clipper; |
| |
| /// {@macro flutter.rendering.ClipRectLayer.clipBehavior} |
| /// |
| /// Defaults to [Clip.hardEdge]. |
| final Clip clipBehavior; |
| |
| @override |
| RenderClipRect createRenderObject(BuildContext context) { |
| return RenderClipRect(clipper: clipper, clipBehavior: clipBehavior); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderClipRect renderObject) { |
| renderObject |
| ..clipper = clipper |
| ..clipBehavior = clipBehavior; |
| } |
| |
| @override |
| void didUnmountRenderObject(RenderClipRect renderObject) { |
| renderObject.clipper = null; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<CustomClipper<Rect>>('clipper', clipper, defaultValue: null)); |
| } |
| } |
| |
| /// A widget that clips its child using a rounded rectangle. |
| /// |
| /// By default, [ClipRRect] uses its own bounds as the base rectangle for the |
| /// clip, but the size and location of the clip can be customized using a custom |
| /// [clipper]. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=eI43jkQkrvs} |
| /// |
| /// {@tool dartpad} |
| /// This example shows various [ClipRRect]s applied to containers. |
| /// |
| /// ** See code in examples/api/lib/widgets/basic/clip_rrect.0.dart ** |
| /// {@end-tool} |
| /// |
| /// ## Troubleshooting |
| /// |
| /// ### Why doesn't my [ClipRRect] child have rounded corners? |
| /// |
| /// When a [ClipRRect] is bigger than the child it contains, its rounded corners |
| /// could be drawn in unexpected positions. Make sure that [ClipRRect] and its child |
| /// have the same bounds (by shrinking the [ClipRRect] with a [FittedBox] or by |
| /// growing the child). |
| /// |
| /// {@tool dartpad} |
| /// This example shows a [ClipRRect] that adds round corners to an image. |
| /// |
| /// ** See code in examples/api/lib/widgets/basic/clip_rrect.1.dart ** |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [CustomClipper], for information about creating custom clips. |
| /// * [ClipRect], for more efficient clips without rounded corners. |
| /// * [ClipOval], for an elliptical clip. |
| /// * [ClipPath], for an arbitrarily shaped clip. |
| class ClipRRect extends SingleChildRenderObjectWidget { |
| /// Creates a rounded-rectangular clip. |
| /// |
| /// The [borderRadius] defaults to [BorderRadius.zero], i.e. a rectangle with |
| /// right-angled corners. |
| /// |
| /// If [clipper] is non-null, then [borderRadius] is ignored. |
| /// |
| /// The [clipBehavior] argument must not be null. If [clipBehavior] is |
| /// [Clip.none], no clipping will be applied. |
| const ClipRRect({ |
| super.key, |
| this.borderRadius = BorderRadius.zero, |
| this.clipper, |
| this.clipBehavior = Clip.antiAlias, |
| super.child, |
| }) : assert(borderRadius != null || clipper != null); |
| |
| /// The border radius of the rounded corners. |
| /// |
| /// Values are clamped so that horizontal and vertical radii sums do not |
| /// exceed width/height. |
| /// |
| /// This value is ignored if [clipper] is non-null. |
| final BorderRadiusGeometry? borderRadius; |
| |
| /// If non-null, determines which clip to use. |
| final CustomClipper<RRect>? clipper; |
| |
| /// {@macro flutter.rendering.ClipRectLayer.clipBehavior} |
| /// |
| /// Defaults to [Clip.antiAlias]. |
| final Clip clipBehavior; |
| |
| @override |
| RenderClipRRect createRenderObject(BuildContext context) { |
| return RenderClipRRect( |
| borderRadius: borderRadius!, |
| clipper: clipper, |
| clipBehavior: clipBehavior, |
| textDirection: Directionality.maybeOf(context), |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderClipRRect renderObject) { |
| renderObject |
| ..borderRadius = borderRadius! |
| ..clipBehavior = clipBehavior |
| ..clipper = clipper |
| ..textDirection = Directionality.maybeOf(context); |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<BorderRadiusGeometry>('borderRadius', borderRadius, showName: false, defaultValue: null)); |
| properties.add(DiagnosticsProperty<CustomClipper<RRect>>('clipper', clipper, defaultValue: null)); |
| } |
| } |
| |
| /// A widget that clips its child using an oval. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=vzWWDO6whIM} |
| /// |
| /// By default, inscribes an axis-aligned oval into its layout dimensions and |
| /// prevents its child from painting outside that oval, but the size and |
| /// location of the clip oval can be customized using a custom [clipper]. |
| /// |
| /// See also: |
| /// |
| /// * [CustomClipper], for information about creating custom clips. |
| /// * [ClipRect], for more efficient clips without rounded corners. |
| /// * [ClipRRect], for a clip with rounded corners. |
| /// * [ClipPath], for an arbitrarily shaped clip. |
| class ClipOval extends SingleChildRenderObjectWidget { |
| /// Creates an oval-shaped clip. |
| /// |
| /// If [clipper] is null, the oval will be inscribed into the layout size and |
| /// position of the child. |
| /// |
| /// The [clipBehavior] argument must not be null. If [clipBehavior] is |
| /// [Clip.none], no clipping will be applied. |
| const ClipOval({ |
| super.key, |
| this.clipper, |
| this.clipBehavior = Clip.antiAlias, |
| super.child, |
| }); |
| |
| /// If non-null, determines which clip to use. |
| /// |
| /// The delegate returns a rectangle that describes the axis-aligned |
| /// bounding box of the oval. The oval's axes will themselves also |
| /// be axis-aligned. |
| /// |
| /// If the [clipper] delegate is null, then the oval uses the |
| /// widget's bounding box (the layout dimensions of the render |
| /// object) instead. |
| final CustomClipper<Rect>? clipper; |
| |
| /// {@macro flutter.rendering.ClipRectLayer.clipBehavior} |
| /// |
| /// Defaults to [Clip.antiAlias]. |
| final Clip clipBehavior; |
| |
| @override |
| RenderClipOval createRenderObject(BuildContext context) { |
| return RenderClipOval(clipper: clipper, clipBehavior: clipBehavior); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderClipOval renderObject) { |
| renderObject |
| ..clipper = clipper |
| ..clipBehavior = clipBehavior; |
| } |
| |
| @override |
| void didUnmountRenderObject(RenderClipOval renderObject) { |
| renderObject.clipper = null; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<CustomClipper<Rect>>('clipper', clipper, defaultValue: null)); |
| } |
| } |
| |
| /// A widget that clips its child using a path. |
| /// |
| /// Calls a callback on a delegate whenever the widget is to be |
| /// painted. The callback returns a path and the widget prevents the |
| /// child from painting outside the path. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=oAUebVIb-7s} |
| /// |
| /// Clipping to a path is expensive. Certain shapes have more |
| /// optimized widgets: |
| /// |
| /// * To clip to a rectangle, consider [ClipRect]. |
| /// * To clip to an oval or circle, consider [ClipOval]. |
| /// * To clip to a rounded rectangle, consider [ClipRRect]. |
| /// |
| /// To clip to a particular [ShapeBorder], consider using either the |
| /// [ClipPath.shape] static method or the [ShapeBorderClipper] custom clipper |
| /// class. |
| class ClipPath extends SingleChildRenderObjectWidget { |
| /// Creates a path clip. |
| /// |
| /// If [clipper] is null, the clip will be a rectangle that matches the layout |
| /// size and location of the child. However, rather than use this default, |
| /// consider using a [ClipRect], which can achieve the same effect more |
| /// efficiently. |
| /// |
| /// The [clipBehavior] argument must not be null. If [clipBehavior] is |
| /// [Clip.none], no clipping will be applied. |
| const ClipPath({ |
| super.key, |
| this.clipper, |
| this.clipBehavior = Clip.antiAlias, |
| super.child, |
| }); |
| |
| /// Creates a shape clip. |
| /// |
| /// Uses a [ShapeBorderClipper] to configure the [ClipPath] to clip to the |
| /// given [ShapeBorder]. |
| static Widget shape({ |
| Key? key, |
| required ShapeBorder shape, |
| Clip clipBehavior = Clip.antiAlias, |
| Widget? child, |
| }) { |
| return Builder( |
| key: key, |
| builder: (BuildContext context) { |
| return ClipPath( |
| clipper: ShapeBorderClipper( |
| shape: shape, |
| textDirection: Directionality.maybeOf(context), |
| ), |
| clipBehavior: clipBehavior, |
| child: child, |
| ); |
| }, |
| ); |
| } |
| |
| /// If non-null, determines which clip to use. |
| /// |
| /// The default clip, which is used if this property is null, is the |
| /// bounding box rectangle of the widget. [ClipRect] is a more |
| /// efficient way of obtaining that effect. |
| final CustomClipper<Path>? clipper; |
| |
| /// {@macro flutter.rendering.ClipRectLayer.clipBehavior} |
| /// |
| /// Defaults to [Clip.antiAlias]. |
| final Clip clipBehavior; |
| |
| @override |
| RenderClipPath createRenderObject(BuildContext context) { |
| return RenderClipPath(clipper: clipper, clipBehavior: clipBehavior); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderClipPath renderObject) { |
| renderObject |
| ..clipper = clipper |
| ..clipBehavior = clipBehavior; |
| } |
| |
| @override |
| void didUnmountRenderObject(RenderClipPath renderObject) { |
| renderObject.clipper = null; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<CustomClipper<Path>>('clipper', clipper, defaultValue: null)); |
| } |
| } |
| |
| /// A widget representing a physical layer that clips its children to a shape. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=XgUOSS30OQk} |
| /// |
| /// Physical layers cast shadows based on an [elevation] which is nominally in |
| /// logical pixels, coming vertically out of the rendering surface. |
| /// |
| /// For shapes that cannot be expressed as a rectangle with rounded corners use |
| /// [PhysicalShape]. |
| /// |
| /// See also: |
| /// |
| /// * [AnimatedPhysicalModel], which animates property changes smoothly over |
| /// a given duration. |
| /// * [DecoratedBox], which can apply more arbitrary shadow effects. |
| /// * [ClipRect], which applies a clip to its child. |
| class PhysicalModel extends SingleChildRenderObjectWidget { |
| /// Creates a physical model with a rounded-rectangular clip. |
| /// |
| /// The [color] is required; physical things have a color. |
| /// |
| /// The [shape], [elevation], [color], [clipBehavior], and [shadowColor] must |
| /// not be null. Additionally, the [elevation] must be non-negative. |
| const PhysicalModel({ |
| super.key, |
| this.shape = BoxShape.rectangle, |
| this.clipBehavior = Clip.none, |
| this.borderRadius, |
| this.elevation = 0.0, |
| required this.color, |
| this.shadowColor = const Color(0xFF000000), |
| super.child, |
| }) : assert(elevation >= 0.0); |
| |
| /// The type of shape. |
| final BoxShape shape; |
| |
| /// {@macro flutter.material.Material.clipBehavior} |
| /// |
| /// Defaults to [Clip.none]. |
| final Clip clipBehavior; |
| |
| /// The border radius of the rounded corners. |
| /// |
| /// Values are clamped so that horizontal and vertical radii sums do not |
| /// exceed width/height. |
| /// |
| /// This is ignored if the [shape] is not [BoxShape.rectangle]. |
| final BorderRadius? borderRadius; |
| |
| /// The z-coordinate relative to the parent at which to place this physical |
| /// object. |
| /// |
| /// The value is non-negative. |
| final double elevation; |
| |
| /// The background color. |
| final Color color; |
| |
| /// The shadow color. |
| final Color shadowColor; |
| |
| @override |
| RenderPhysicalModel createRenderObject(BuildContext context) { |
| return RenderPhysicalModel( |
| shape: shape, |
| clipBehavior: clipBehavior, |
| borderRadius: borderRadius, |
| elevation: elevation, |
| color: color, |
| shadowColor: shadowColor, |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderPhysicalModel renderObject) { |
| renderObject |
| ..shape = shape |
| ..clipBehavior = clipBehavior |
| ..borderRadius = borderRadius |
| ..elevation = elevation |
| ..color = color |
| ..shadowColor = shadowColor; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(EnumProperty<BoxShape>('shape', shape)); |
| properties.add(DiagnosticsProperty<BorderRadius>('borderRadius', borderRadius)); |
| properties.add(DoubleProperty('elevation', elevation)); |
| properties.add(ColorProperty('color', color)); |
| properties.add(ColorProperty('shadowColor', shadowColor)); |
| } |
| } |
| |
| /// A widget representing a physical layer that clips its children to a path. |
| /// |
| /// Physical layers cast shadows based on an [elevation] which is nominally in |
| /// logical pixels, coming vertically out of the rendering surface. |
| /// |
| /// [PhysicalModel] does the same but only supports shapes that can be expressed |
| /// as rectangles with rounded corners. |
| /// |
| /// {@tool dartpad} |
| /// This example shows how to use a [PhysicalShape] on a centered [SizedBox] |
| /// to clip it to a rounded rectangle using a [ShapeBorderClipper] and give it |
| /// an orange color along with a shadow. |
| /// |
| /// ** See code in examples/api/lib/widgets/basic/physical_shape.0.dart ** |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [ShapeBorderClipper], which converts a [ShapeBorder] to a [CustomClipper], as |
| /// needed by this widget. |
| class PhysicalShape extends SingleChildRenderObjectWidget { |
| /// Creates a physical model with an arbitrary shape clip. |
| /// |
| /// The [color] is required; physical things have a color. |
| /// |
| /// The [clipper], [elevation], [color], [clipBehavior], and [shadowColor] |
| /// must not be null. Additionally, the [elevation] must be non-negative. |
| const PhysicalShape({ |
| super.key, |
| required this.clipper, |
| this.clipBehavior = Clip.none, |
| this.elevation = 0.0, |
| required this.color, |
| this.shadowColor = const Color(0xFF000000), |
| super.child, |
| }) : assert(elevation >= 0.0); |
| |
| /// Determines which clip to use. |
| /// |
| /// If the path in question is expressed as a [ShapeBorder] subclass, |
| /// consider using the [ShapeBorderClipper] delegate class to adapt the |
| /// shape for use with this widget. |
| final CustomClipper<Path> clipper; |
| |
| /// {@macro flutter.material.Material.clipBehavior} |
| /// |
| /// Defaults to [Clip.none]. |
| final Clip clipBehavior; |
| |
| /// The z-coordinate relative to the parent at which to place this physical |
| /// object. |
| /// |
| /// The value is non-negative. |
| final double elevation; |
| |
| /// The background color. |
| final Color color; |
| |
| /// When elevation is non zero the color to use for the shadow color. |
| final Color shadowColor; |
| |
| @override |
| RenderPhysicalShape createRenderObject(BuildContext context) { |
| return RenderPhysicalShape( |
| clipper: clipper, |
| clipBehavior: clipBehavior, |
| elevation: elevation, |
| color: color, |
| shadowColor: shadowColor, |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderPhysicalShape renderObject) { |
| renderObject |
| ..clipper = clipper |
| ..clipBehavior = clipBehavior |
| ..elevation = elevation |
| ..color = color |
| ..shadowColor = shadowColor; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<CustomClipper<Path>>('clipper', clipper)); |
| properties.add(DoubleProperty('elevation', elevation)); |
| properties.add(ColorProperty('color', color)); |
| properties.add(ColorProperty('shadowColor', shadowColor)); |
| } |
| } |
| |
| // POSITIONING AND SIZING NODES |
| |
| /// A widget that applies a transformation before painting its child. |
| /// |
| /// Unlike [RotatedBox], which applies a rotation prior to layout, this object |
| /// applies its transformation just prior to painting, which means the |
| /// transformation is not taken into account when calculating how much space |
| /// this widget's child (and thus this widget) consumes. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=9z_YNlRlWfA} |
| /// |
| /// {@tool snippet} |
| /// |
| /// This example rotates and skews an orange box containing text, keeping the |
| /// top right corner pinned to its original position. |
| /// |
| /// ```dart |
| /// ColoredBox( |
| /// color: Colors.black, |
| /// child: Transform( |
| /// alignment: Alignment.topRight, |
| /// transform: Matrix4.skewY(0.3)..rotateZ(-math.pi / 12.0), |
| /// child: Container( |
| /// padding: const EdgeInsets.all(8.0), |
| /// color: const Color(0xFFE8581C), |
| /// child: const Text('Apartment for rent!'), |
| /// ), |
| /// ), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [RotatedBox], which rotates the child widget during layout, not just |
| /// during painting. |
| /// * [FractionalTranslation], which applies a translation to the child |
| /// that is relative to the child's size. |
| /// * [FittedBox], which sizes and positions its child widget to fit the parent |
| /// according to a given [BoxFit] discipline. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class Transform extends SingleChildRenderObjectWidget { |
| /// Creates a widget that transforms its child. |
| /// |
| /// The [transform] argument must not be null. |
| const Transform({ |
| super.key, |
| required this.transform, |
| this.origin, |
| this.alignment, |
| this.transformHitTests = true, |
| this.filterQuality, |
| super.child, |
| }); |
| |
| /// Creates a widget that transforms its child using a rotation around the |
| /// center. |
| /// |
| /// The `angle` argument must not be null. It gives the rotation in clockwise |
| /// radians. |
| /// |
| /// {@tool snippet} |
| /// |
| /// This example rotates an orange box containing text around its center by |
| /// fifteen degrees. |
| /// |
| /// ```dart |
| /// Transform.rotate( |
| /// angle: -math.pi / 12.0, |
| /// child: Container( |
| /// padding: const EdgeInsets.all(8.0), |
| /// color: const Color(0xFFE8581C), |
| /// child: const Text('Apartment for rent!'), |
| /// ), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [RotationTransition], which animates changes in rotation smoothly |
| /// over a given duration. |
| Transform.rotate({ |
| super.key, |
| required double angle, |
| this.origin, |
| this.alignment = Alignment.center, |
| this.transformHitTests = true, |
| this.filterQuality, |
| super.child, |
| }) : transform = _computeRotation(angle); |
| |
| /// Creates a widget that transforms its child using a translation. |
| /// |
| /// The `offset` argument must not be null. It specifies the translation. |
| /// |
| /// {@tool snippet} |
| /// |
| /// This example shifts the silver-colored child down by fifteen pixels. |
| /// |
| /// ```dart |
| /// Transform.translate( |
| /// offset: const Offset(0.0, 15.0), |
| /// child: Container( |
| /// padding: const EdgeInsets.all(8.0), |
| /// color: const Color(0xFF7F7F7F), |
| /// child: const Text('Quarter'), |
| /// ), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| Transform.translate({ |
| super.key, |
| required Offset offset, |
| this.transformHitTests = true, |
| this.filterQuality, |
| super.child, |
| }) : transform = Matrix4.translationValues(offset.dx, offset.dy, 0.0), |
| origin = null, |
| alignment = null; |
| |
| /// Creates a widget that scales its child along the 2D plane. |
| /// |
| /// The `scaleX` argument provides the scalar by which to multiply the `x` axis, and the `scaleY` argument provides the scalar by which to multiply the `y` axis. Either may be omitted, in which case that axis defaults to 1.0. |
| /// |
| /// For convenience, to scale the child uniformly, instead of providing `scaleX` and `scaleY`, the `scale` parameter may be used. |
| /// |
| /// At least one of `scale`, `scaleX`, and `scaleY` must be non-null. If `scale` is provided, the other two must be null; similarly, if it is not provided, one of the other two must be provided. |
| /// |
| /// The [alignment] controls the origin of the scale; by default, this is |
| /// the center of the box. |
| /// |
| /// {@tool snippet} |
| /// |
| /// This example shrinks an orange box containing text such that each dimension |
| /// is half the size it would otherwise be. |
| /// |
| /// ```dart |
| /// Transform.scale( |
| /// scale: 0.5, |
| /// child: Container( |
| /// padding: const EdgeInsets.all(8.0), |
| /// color: const Color(0xFFE8581C), |
| /// child: const Text('Bad Idea Bears'), |
| /// ), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [ScaleTransition], which animates changes in scale smoothly |
| /// over a given duration. |
| Transform.scale({ |
| super.key, |
| double? scale, |
| double? scaleX, |
| double? scaleY, |
| this.origin, |
| this.alignment = Alignment.center, |
| this.transformHitTests = true, |
| this.filterQuality, |
| super.child, |
| }) : assert(!(scale == null && scaleX == null && scaleY == null), "At least one of 'scale', 'scaleX' and 'scaleY' is required to be non-null"), |
| assert(scale == null || (scaleX == null && scaleY == null), "If 'scale' is non-null then 'scaleX' and 'scaleY' must be left null"), |
| transform = Matrix4.diagonal3Values(scale ?? scaleX ?? 1.0, scale ?? scaleY ?? 1.0, 1.0); |
| |
| /// Creates a widget that mirrors its child about the widget's center point. |
| /// |
| /// If `flipX` is true, the child widget will be flipped horizontally. Defaults to false. |
| /// |
| /// If `flipY` is true, the child widget will be flipped vertically. Defaults to false. |
| /// |
| /// If both are true, the child widget will be flipped both vertically and horizontally, equivalent to a 180 degree rotation. |
| /// |
| /// {@tool snippet} |
| /// |
| /// This example flips the text horizontally. |
| /// |
| /// ```dart |
| /// Transform.flip( |
| /// flipX: true, |
| /// child: const Text('Horizontal Flip'), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| Transform.flip({ |
| super.key, |
| bool flipX = false, |
| bool flipY = false, |
| this.origin, |
| this.transformHitTests = true, |
| this.filterQuality, |
| super.child, |
| }) : alignment = Alignment.center, |
| transform = Matrix4.diagonal3Values(flipX ? -1.0 : 1.0, flipY ? -1.0 : 1.0, 1.0); |
| |
| // Computes a rotation matrix for an angle in radians, attempting to keep rotations |
| // at integral values for angles of 0, π/2, π, 3π/2. |
| static Matrix4 _computeRotation(double radians) { |
| assert(radians.isFinite, 'Cannot compute the rotation matrix for a non-finite angle: $radians'); |
| if (radians == 0.0) { |
| return Matrix4.identity(); |
| } |
| final double sin = math.sin(radians); |
| if (sin == 1.0) { |
| return _createZRotation(1.0, 0.0); |
| } |
| if (sin == -1.0) { |
| return _createZRotation(-1.0, 0.0); |
| } |
| final double cos = math.cos(radians); |
| if (cos == -1.0) { |
| return _createZRotation(0.0, -1.0); |
| } |
| return _createZRotation(sin, cos); |
| } |
| |
| static Matrix4 _createZRotation(double sin, double cos) { |
| final Matrix4 result = Matrix4.zero(); |
| result.storage[0] = cos; |
| result.storage[1] = sin; |
| result.storage[4] = -sin; |
| result.storage[5] = cos; |
| result.storage[10] = 1.0; |
| result.storage[15] = 1.0; |
| return result; |
| } |
| |
| /// The matrix to transform the child by during painting. |
| final Matrix4 transform; |
| |
| /// The origin of the coordinate system (relative to the upper left corner of |
| /// this render object) in which to apply the matrix. |
| /// |
| /// Setting an origin is equivalent to conjugating the transform matrix by a |
| /// translation. This property is provided just for convenience. |
| final Offset? origin; |
| |
| /// The alignment of the origin, relative to the size of the box. |
| /// |
| /// This is equivalent to setting an origin based on the size of the box. |
| /// If it is specified at the same time as the [origin], both are applied. |
| /// |
| /// An [AlignmentDirectional.centerStart] value is the same as an [Alignment] |
| /// whose [Alignment.x] value is `-1.0` if [Directionality.of] returns |
| /// [TextDirection.ltr], and `1.0` if [Directionality.of] returns |
| /// [TextDirection.rtl]. Similarly [AlignmentDirectional.centerEnd] is the |
| /// same as an [Alignment] whose [Alignment.x] value is `1.0` if |
| /// [Directionality.of] returns [TextDirection.ltr], and `-1.0` if |
| /// [Directionality.of] returns [TextDirection.rtl]. |
| final AlignmentGeometry? alignment; |
| |
| /// Whether to apply the transformation when performing hit tests. |
| final bool transformHitTests; |
| |
| /// The filter quality with which to apply the transform as a bitmap operation. |
| /// |
| /// {@template flutter.widgets.Transform.optional.FilterQuality} |
| /// The transform will be applied by re-rendering the child if [filterQuality] is null, |
| /// otherwise it controls the quality of an [ImageFilter.matrix] applied to a bitmap |
| /// rendering of the child. |
| /// {@endtemplate} |
| final FilterQuality? filterQuality; |
| |
| @override |
| RenderTransform createRenderObject(BuildContext context) { |
| return RenderTransform( |
| transform: transform, |
| origin: origin, |
| alignment: alignment, |
| textDirection: Directionality.maybeOf(context), |
| transformHitTests: transformHitTests, |
| filterQuality: filterQuality, |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderTransform renderObject) { |
| renderObject |
| ..transform = transform |
| ..origin = origin |
| ..alignment = alignment |
| ..textDirection = Directionality.maybeOf(context) |
| ..transformHitTests = transformHitTests |
| ..filterQuality = filterQuality; |
| } |
| } |
| |
| /// A widget that can be targeted by a [CompositedTransformFollower]. |
| /// |
| /// When this widget is composited during the compositing phase (which comes |
| /// after the paint phase, as described in [WidgetsBinding.drawFrame]), it |
| /// updates the [link] object so that any [CompositedTransformFollower] widgets |
| /// that are subsequently composited in the same frame and were given the same |
| /// [LayerLink] can position themselves at the same screen location. |
| /// |
| /// A single [CompositedTransformTarget] can be followed by multiple |
| /// [CompositedTransformFollower] widgets. |
| /// |
| /// The [CompositedTransformTarget] must come earlier in the paint order than |
| /// any linked [CompositedTransformFollower]s. |
| /// |
| /// See also: |
| /// |
| /// * [CompositedTransformFollower], the widget that can target this one. |
| /// * [LeaderLayer], the layer that implements this widget's logic. |
| class CompositedTransformTarget extends SingleChildRenderObjectWidget { |
| /// Creates a composited transform target widget. |
| /// |
| /// The [link] property must not be null, and must not be currently being used |
| /// by any other [CompositedTransformTarget] object that is in the tree. |
| const CompositedTransformTarget({ |
| super.key, |
| required this.link, |
| super.child, |
| }); |
| |
| /// The link object that connects this [CompositedTransformTarget] with one or |
| /// more [CompositedTransformFollower]s. |
| /// |
| /// This property must not be null. The object must not be associated with |
| /// another [CompositedTransformTarget] that is also being painted. |
| final LayerLink link; |
| |
| @override |
| RenderLeaderLayer createRenderObject(BuildContext context) { |
| return RenderLeaderLayer( |
| link: link, |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderLeaderLayer renderObject) { |
| renderObject.link = link; |
| } |
| } |
| |
| /// A widget that follows a [CompositedTransformTarget]. |
| /// |
| /// When this widget is composited during the compositing phase (which comes |
| /// after the paint phase, as described in [WidgetsBinding.drawFrame]), it |
| /// applies a transformation that brings [targetAnchor] of the linked |
| /// [CompositedTransformTarget] and [followerAnchor] of this widget together. |
| /// The two anchor points will have the same global coordinates, unless [offset] |
| /// is not [Offset.zero], in which case [followerAnchor] will be offset by |
| /// [offset] in the linked [CompositedTransformTarget]'s coordinate space. |
| /// |
| /// The [LayerLink] object used as the [link] must be the same object as that |
| /// provided to the matching [CompositedTransformTarget]. |
| /// |
| /// The [CompositedTransformTarget] must come earlier in the paint order than |
| /// this [CompositedTransformFollower]. |
| /// |
| /// Hit testing on descendants of this widget will only work if the target |
| /// position is within the box that this widget's parent considers to be |
| /// hittable. If the parent covers the screen, this is trivially achievable, so |
| /// this widget is usually used as the root of an [OverlayEntry] in an app-wide |
| /// [Overlay] (e.g. as created by the [MaterialApp] widget's [Navigator]). |
| /// |
| /// See also: |
| /// |
| /// * [CompositedTransformTarget], the widget that this widget can target. |
| /// * [FollowerLayer], the layer that implements this widget's logic. |
| /// * [Transform], which applies an arbitrary transform to a child. |
| class CompositedTransformFollower extends SingleChildRenderObjectWidget { |
| /// Creates a composited transform target widget. |
| /// |
| /// The [link] property must not be null. If it was also provided to a |
| /// [CompositedTransformTarget], that widget must come earlier in the paint |
| /// order. |
| /// |
| /// The [showWhenUnlinked] and [offset] properties must also not be null. |
| const CompositedTransformFollower({ |
| super.key, |
| required this.link, |
| this.showWhenUnlinked = true, |
| this.offset = Offset.zero, |
| this.targetAnchor = Alignment.topLeft, |
| this.followerAnchor = Alignment.topLeft, |
| super.child, |
| }); |
| |
| /// The link object that connects this [CompositedTransformFollower] with a |
| /// [CompositedTransformTarget]. |
| /// |
| /// This property must not be null. |
| final LayerLink link; |
| |
| /// Whether to show the widget's contents when there is no corresponding |
| /// [CompositedTransformTarget] with the same [link]. |
| /// |
| /// When the widget is linked, the child is positioned such that it has the |
| /// same global position as the linked [CompositedTransformTarget]. |
| /// |
| /// When the widget is not linked, then: if [showWhenUnlinked] is true, the |
| /// child is visible and not repositioned; if it is false, then child is |
| /// hidden. |
| final bool showWhenUnlinked; |
| |
| /// The anchor point on the linked [CompositedTransformTarget] that |
| /// [followerAnchor] will line up with. |
| /// |
| /// {@template flutter.widgets.CompositedTransformFollower.targetAnchor} |
| /// For example, when [targetAnchor] and [followerAnchor] are both |
| /// [Alignment.topLeft], this widget will be top left aligned with the linked |
| /// [CompositedTransformTarget]. When [targetAnchor] is |
| /// [Alignment.bottomLeft] and [followerAnchor] is [Alignment.topLeft], this |
| /// widget will be left aligned with the linked [CompositedTransformTarget], |
| /// and its top edge will line up with the [CompositedTransformTarget]'s |
| /// bottom edge. |
| /// {@endtemplate} |
| /// |
| /// Defaults to [Alignment.topLeft]. |
| final Alignment targetAnchor; |
| |
| /// The anchor point on this widget that will line up with [targetAnchor] on |
| /// the linked [CompositedTransformTarget]. |
| /// |
| /// {@macro flutter.widgets.CompositedTransformFollower.targetAnchor} |
| /// |
| /// Defaults to [Alignment.topLeft]. |
| final Alignment followerAnchor; |
| |
| /// The additional offset to apply to the [targetAnchor] of the linked |
| /// [CompositedTransformTarget] to obtain this widget's [followerAnchor] |
| /// position. |
| final Offset offset; |
| |
| @override |
| RenderFollowerLayer createRenderObject(BuildContext context) { |
| return RenderFollowerLayer( |
| link: link, |
| showWhenUnlinked: showWhenUnlinked, |
| offset: offset, |
| leaderAnchor: targetAnchor, |
| followerAnchor: followerAnchor, |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderFollowerLayer renderObject) { |
| renderObject |
| ..link = link |
| ..showWhenUnlinked = showWhenUnlinked |
| ..offset = offset |
| ..leaderAnchor = targetAnchor |
| ..followerAnchor = followerAnchor; |
| } |
| } |
| |
| /// Scales and positions its child within itself according to [fit]. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=T4Uehk3_wlY} |
| /// |
| /// {@tool dartpad} |
| /// In this example, the image is stretched to fill the entire [Container], which would |
| /// not happen normally without using FittedBox. |
| /// |
| /// ** See code in examples/api/lib/widgets/basic/fitted_box.0.dart ** |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [Transform], which applies an arbitrary transform to its child widget at |
| /// paint time. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class FittedBox extends SingleChildRenderObjectWidget { |
| /// Creates a widget that scales and positions its child within itself according to [fit]. |
| /// |
| /// The [fit] and [alignment] arguments must not be null. |
| const FittedBox({ |
| super.key, |
| this.fit = BoxFit.contain, |
| this.alignment = Alignment.center, |
| this.clipBehavior = Clip.none, |
| super.child, |
| }); |
| |
| /// How to inscribe the child into the space allocated during layout. |
| final BoxFit fit; |
| |
| /// How to align the child within its parent's bounds. |
| /// |
| /// An alignment of (-1.0, -1.0) aligns the child to the top-left corner of its |
| /// parent's bounds. An alignment of (1.0, 0.0) aligns the child to the middle |
| /// of the right edge of its parent's bounds. |
| /// |
| /// Defaults to [Alignment.center]. |
| /// |
| /// See also: |
| /// |
| /// * [Alignment], a class with convenient constants typically used to |
| /// specify an [AlignmentGeometry]. |
| /// * [AlignmentDirectional], like [Alignment] for specifying alignments |
| /// relative to text direction. |
| final AlignmentGeometry alignment; |
| |
| /// {@macro flutter.material.Material.clipBehavior} |
| /// |
| /// Defaults to [Clip.none]. |
| final Clip clipBehavior; |
| |
| @override |
| RenderFittedBox createRenderObject(BuildContext context) { |
| return RenderFittedBox( |
| fit: fit, |
| alignment: alignment, |
| textDirection: Directionality.maybeOf(context), |
| clipBehavior: clipBehavior, |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderFittedBox renderObject) { |
| renderObject |
| ..fit = fit |
| ..alignment = alignment |
| ..textDirection = Directionality.maybeOf(context) |
| ..clipBehavior = clipBehavior; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(EnumProperty<BoxFit>('fit', fit)); |
| properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); |
| } |
| } |
| |
| /// Applies a translation transformation before painting its child. |
| /// |
| /// The translation is expressed as a [Offset] scaled to the child's size. For |
| /// example, an [Offset] with a `dx` of 0.25 will result in a horizontal |
| /// translation of one quarter the width of the child. |
| /// |
| /// Hit tests will only be detected inside the bounds of the |
| /// [FractionalTranslation], even if the contents are offset such that |
| /// they overflow. |
| /// |
| /// See also: |
| /// |
| /// * [Transform], which applies an arbitrary transform to its child widget at |
| /// paint time. |
| /// * [Transform.translate], which applies an absolute offset translation |
| /// transformation instead of an offset scaled to the child. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class FractionalTranslation extends SingleChildRenderObjectWidget { |
| /// Creates a widget that translates its child's painting. |
| /// |
| /// The [translation] argument must not be null. |
| const FractionalTranslation({ |
| super.key, |
| required this.translation, |
| this.transformHitTests = true, |
| super.child, |
| }); |
| |
| /// The translation to apply to the child, scaled to the child's size. |
| /// |
| /// For example, an [Offset] with a `dx` of 0.25 will result in a horizontal |
| /// translation of one quarter the width of the child. |
| final Offset translation; |
| |
| /// Whether to apply the translation when performing hit tests. |
| final bool transformHitTests; |
| |
| @override |
| RenderFractionalTranslation createRenderObject(BuildContext context) { |
| return RenderFractionalTranslation( |
| translation: translation, |
| transformHitTests: transformHitTests, |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderFractionalTranslation renderObject) { |
| renderObject |
| ..translation = translation |
| ..transformHitTests = transformHitTests; |
| } |
| } |
| |
| /// A widget that rotates its child by a integral number of quarter turns. |
| /// |
| /// Unlike [Transform], which applies a transform just prior to painting, |
| /// this object applies its rotation prior to layout, which means the entire |
| /// rotated box consumes only as much space as required by the rotated child. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=BFE6_UglLfQ} |
| /// |
| /// {@tool snippet} |
| /// |
| /// This snippet rotates the child (some [Text]) so that it renders from bottom |
| /// to top, like an axis label on a graph: |
| /// |
| /// ```dart |
| /// const RotatedBox( |
| /// quarterTurns: 3, |
| /// child: Text('Hello World!'), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [Transform], which is a paint effect that allows you to apply an |
| /// arbitrary transform to a child. |
| /// * [Transform.rotate], which applies a rotation paint effect. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class RotatedBox extends SingleChildRenderObjectWidget { |
| /// A widget that rotates its child. |
| /// |
| /// The [quarterTurns] argument must not be null. |
| const RotatedBox({ |
| super.key, |
| required this.quarterTurns, |
| super.child, |
| }); |
| |
| /// The number of clockwise quarter turns the child should be rotated. |
| final int quarterTurns; |
| |
| @override |
| RenderRotatedBox createRenderObject(BuildContext context) => RenderRotatedBox(quarterTurns: quarterTurns); |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderRotatedBox renderObject) { |
| renderObject.quarterTurns = quarterTurns; |
| } |
| } |
| |
| /// A widget that insets its child by the given padding. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=oD5RtLhhubg} |
| /// |
| /// When passing layout constraints to its child, padding shrinks the |
| /// constraints by the given padding, causing the child to layout at a smaller |
| /// size. Padding then sizes itself to its child's size, inflated by the |
| /// padding, effectively creating empty space around the child. |
| /// |
| /// {@tool snippet} |
| /// |
| /// This snippet creates "Hello World!" [Text] inside a [Card] that is indented |
| /// by sixteen pixels in each direction. |
| /// |
| /// ![](https://flutter.github.io/assets-for-api-docs/assets/widgets/padding.png) |
| /// |
| /// ```dart |
| /// const Card( |
| /// child: Padding( |
| /// padding: EdgeInsets.all(16.0), |
| /// child: Text('Hello World!'), |
| /// ), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// ## Design discussion |
| /// |
| /// ### Why use a [Padding] widget rather than a [Container] with a [Container.padding] property? |
| /// |
| /// There isn't really any difference between the two. If you supply a |
| /// [Container.padding] argument, [Container] builds a [Padding] widget |
| /// for you. |
| /// |
| /// [Container] doesn't implement its properties directly. Instead, [Container] |
| /// combines a number of simpler widgets together into a convenient package. For |
| /// example, the [Container.padding] property causes the container to build a |
| /// [Padding] widget and the [Container.decoration] property causes the |
| /// container to build a [DecoratedBox] widget. If you find [Container] |
| /// convenient, feel free to use it. If not, feel free to build these simpler |
| /// widgets in whatever combination meets your needs. |
| /// |
| /// In fact, the majority of widgets in Flutter are combinations of other |
| /// simpler widgets. Composition, rather than inheritance, is the primary |
| /// mechanism for building up widgets. |
| /// |
| /// See also: |
| /// |
| /// * [AnimatedPadding], which animates changes in [padding] over a given |
| /// duration. |
| /// * [EdgeInsets], the class that is used to describe the padding dimensions. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class Padding extends SingleChildRenderObjectWidget { |
| /// Creates a widget that insets its child. |
| /// |
| /// The [padding] argument must not be null. |
| const Padding({ |
| super.key, |
| required this.padding, |
| super.child, |
| }); |
| |
| /// The amount of space by which to inset the child. |
| final EdgeInsetsGeometry padding; |
| |
| @override |
| RenderPadding createRenderObject(BuildContext context) { |
| return RenderPadding( |
| padding: padding, |
| textDirection: Directionality.maybeOf(context), |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderPadding renderObject) { |
| renderObject |
| ..padding = padding |
| ..textDirection = Directionality.maybeOf(context); |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding)); |
| } |
| } |
| |
| /// A widget that aligns its child within itself and optionally sizes itself |
| /// based on the child's size. |
| /// |
| /// For example, to align a box at the bottom right, you would pass this box a |
| /// tight constraint that is bigger than the child's natural size, |
| /// with an alignment of [Alignment.bottomRight]. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=g2E7yl3MwMk} |
| /// |
| /// This widget will be as big as possible if its dimensions are constrained and |
| /// [widthFactor] and [heightFactor] are null. If a dimension is unconstrained |
| /// and the corresponding size factor is null then the widget will match its |
| /// child's size in that dimension. If a size factor is non-null then the |
| /// corresponding dimension of this widget will be the product of the child's |
| /// dimension and the size factor. For example if widthFactor is 2.0 then |
| /// the width of this widget will always be twice its child's width. |
| /// |
| /// ## How it works |
| /// |
| /// The [alignment] property describes a point in the `child`'s coordinate system |
| /// and a different point in the coordinate system of this widget. The [Align] |
| /// widget positions the `child` such that both points are lined up on top of |
| /// each other. |
| /// |
| /// {@tool snippet} |
| /// The [Align] widget in this example uses one of the defined constants from |
| /// [Alignment], [Alignment.topRight]. This places the [FlutterLogo] in the top |
| /// right corner of the parent blue [Container]. |
| /// |
| /// ![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) |
| /// |
| /// ```dart |
| /// Center( |
| /// child: Container( |
| /// height: 120.0, |
| /// width: 120.0, |
| /// color: Colors.blue[50], |
| /// child: const Align( |
| /// alignment: Alignment.topRight, |
| /// child: FlutterLogo( |
| /// size: 60, |
| /// ), |
| /// ), |
| /// ), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// {@tool snippet} |
| /// The [Alignment] used in the following example defines a single point: |
| /// |
| /// * (0.2 * width of [FlutterLogo]/2 + width of [FlutterLogo]/2, 0.6 * height |
| /// of [FlutterLogo]/2 + height of [FlutterLogo]/2) = (36.0, 48.0). |
| /// |
| /// The [Alignment] class uses a coordinate system with an origin in the center |
| /// of the [Container], as shown with the [Icon] above. [Align] will place the |
| /// [FlutterLogo] at (36.0, 48.0) according to this coordinate system. |
| /// |
| /// ![A blue square container with the Flutter logo positioned according to the |
| /// Alignment specified above. A point is marked at the center of the container |
| /// for the origin of the Alignment coordinate system.](https://flutter.github.io/assets-for-api-docs/assets/widgets/align_alignment.png) |
| /// |
| /// ```dart |
| /// Center( |
| /// child: Container( |
| /// height: 120.0, |
| /// width: 120.0, |
| /// color: Colors.blue[50], |
| /// child: const Align( |
| /// alignment: Alignment(0.2, 0.6), |
| /// child: FlutterLogo( |
| /// size: 60, |
| /// ), |
| /// ), |
| /// ), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// {@tool snippet} |
| /// The [FractionalOffset] used in the following example defines two points: |
| /// |
| /// * (0.2 * width of [FlutterLogo], 0.6 * height of [FlutterLogo]) = (12.0, 36.0) |
| /// in the coordinate system of the blue container. |
| /// * (0.2 * width of [Align], 0.6 * height of [Align]) = (24.0, 72.0) in the |
| /// coordinate system of the [Align] widget. |
| /// |
| /// The [Align] widget positions the [FlutterLogo] such that the two points are on |
| /// top of each other. In this example, the top left of the [FlutterLogo] will |
| /// be placed at (24.0, 72.0) - (12.0, 36.0) = (12.0, 36.0) from the top left of |
| /// the [Align] widget. |
| /// |
| /// The [FractionalOffset] class uses a coordinate system with an origin in the top-left |
| /// corner of the [Container] in difference to the center-oriented system used in |
| /// the example above with [Alignment]. |
| /// |
| /// ![A blue square container with the Flutter logo positioned according to the |
| /// FractionalOffset specified above. A point is marked at the top left corner |
| /// 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) |
| /// |
| /// ```dart |
| /// Center( |
| /// child: Container( |
| /// height: 120.0, |
| /// width: 120.0, |
| /// color: Colors.blue[50], |
| /// child: const Align( |
| /// alignment: FractionalOffset(0.2, 0.6), |
| /// child: FlutterLogo( |
| /// size: 60, |
| /// ), |
| /// ), |
| /// ), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [AnimatedAlign], which animates changes in [alignment] smoothly over a |
| /// given duration. |
| /// * [CustomSingleChildLayout], which uses a delegate to control the layout of |
| /// a single child. |
| /// * [Center], which is the same as [Align] but with the [alignment] always |
| /// set to [Alignment.center]. |
| /// * [FractionallySizedBox], which sizes its child based on a fraction of its |
| /// own size and positions the child according to an [Alignment] value. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class Align extends SingleChildRenderObjectWidget { |
| /// Creates an alignment widget. |
| /// |
| /// The alignment defaults to [Alignment.center]. |
| const Align({ |
| super.key, |
| this.alignment = Alignment.center, |
| this.widthFactor, |
| this.heightFactor, |
| super.child, |
| }) : assert(widthFactor == null || widthFactor >= 0.0), |
| assert(heightFactor == null || heightFactor >= 0.0); |
| |
| /// How to align the child. |
| /// |
| /// The x and y values of the [Alignment] control the horizontal and vertical |
| /// alignment, respectively. An x value of -1.0 means that the left edge of |
| /// the child is aligned with the left edge of the parent whereas an x value |
| /// of 1.0 means that the right edge of the child is aligned with the right |
| /// edge of the parent. Other values interpolate (and extrapolate) linearly. |
| /// For example, a value of 0.0 means that the center of the child is aligned |
| /// with the center of the parent. |
| /// |
| /// See also: |
| /// |
| /// * [Alignment], which has more details and some convenience constants for |
| /// common positions. |
| /// * [AlignmentDirectional], which has a horizontal coordinate orientation |
| /// that depends on the [TextDirection]. |
| final AlignmentGeometry alignment; |
| |
| /// If non-null, sets its width to the child's width multiplied by this factor. |
| /// |
| /// Can be both greater and less than 1.0 but must be non-negative. |
| final double? widthFactor; |
| |
| /// If non-null, sets its height to the child's height multiplied by this factor. |
| /// |
| /// Can be both greater and less than 1.0 but must be non-negative. |
| final double? heightFactor; |
| |
| @override |
| RenderPositionedBox createRenderObject(BuildContext context) { |
| return RenderPositionedBox( |
| alignment: alignment, |
| widthFactor: widthFactor, |
| heightFactor: heightFactor, |
| textDirection: Directionality.maybeOf(context), |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderPositionedBox renderObject) { |
| renderObject |
| ..alignment = alignment |
| ..widthFactor = widthFactor |
| ..heightFactor = heightFactor |
| ..textDirection = Directionality.maybeOf(context); |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); |
| properties.add(DoubleProperty('widthFactor', widthFactor, defaultValue: null)); |
| properties.add(DoubleProperty('heightFactor', heightFactor, defaultValue: null)); |
| } |
| } |
| |
| /// A widget that centers its child within itself. |
| /// |
| /// This widget will be as big as possible if its dimensions are constrained and |
| /// [widthFactor] and [heightFactor] are null. If a dimension is unconstrained |
| /// and the corresponding size factor is null then the widget will match its |
| /// child's size in that dimension. If a size factor is non-null then the |
| /// corresponding dimension of this widget will be the product of the child's |
| /// dimension and the size factor. For example if widthFactor is 2.0 then |
| /// the width of this widget will always be twice its child's width. |
| /// |
| /// See also: |
| /// |
| /// * [Align], which lets you arbitrarily position a child within itself, |
| /// rather than just centering it. |
| /// * [Row], a widget that displays its children in a horizontal array. |
| /// * [Column], a widget that displays its children in a vertical array. |
| /// * [Container], a convenience widget that combines common painting, |
| /// positioning, and sizing widgets. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class Center extends Align { |
| /// Creates a widget that centers its child. |
| const Center({ super.key, super.widthFactor, super.heightFactor, super.child }); |
| } |
| |
| /// A widget that defers the layout of its single child to a delegate. |
| /// |
| /// The delegate can determine the layout constraints for the child and can |
| /// decide where to position the child. The delegate can also determine the size |
| /// of the parent, but the size of the parent cannot depend on the size of the |
| /// child. |
| /// |
| /// See also: |
| /// |
| /// * [SingleChildLayoutDelegate], which controls the layout of the child. |
| /// * [Align], which sizes itself based on its child's size and positions |
| /// the child according to an [Alignment] value. |
| /// * [FractionallySizedBox], which sizes its child based on a fraction of its own |
| /// size and positions the child according to an [Alignment] value. |
| /// * [CustomMultiChildLayout], which uses a delegate to position multiple |
| /// children. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class CustomSingleChildLayout extends SingleChildRenderObjectWidget { |
| /// Creates a custom single child layout. |
| /// |
| /// The [delegate] argument must not be null. |
| const CustomSingleChildLayout({ |
| super.key, |
| required this.delegate, |
| super.child, |
| }); |
| |
| /// The delegate that controls the layout of the child. |
| final SingleChildLayoutDelegate delegate; |
| |
| @override |
| RenderCustomSingleChildLayoutBox createRenderObject(BuildContext context) { |
| return RenderCustomSingleChildLayoutBox(delegate: delegate); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderCustomSingleChildLayoutBox renderObject) { |
| renderObject.delegate = delegate; |
| } |
| } |
| |
| /// Metadata for identifying children in a [CustomMultiChildLayout]. |
| /// |
| /// The [MultiChildLayoutDelegate.hasChild], |
| /// [MultiChildLayoutDelegate.layoutChild], and |
| /// [MultiChildLayoutDelegate.positionChild] methods use these identifiers. |
| class LayoutId extends ParentDataWidget<MultiChildLayoutParentData> { |
| /// Marks a child with a layout identifier. |
| /// |
| /// Both the child and the id arguments must not be null. |
| LayoutId({ |
| Key? key, |
| required this.id, |
| required super.child, |
| }) : super(key: key ?? ValueKey<Object>(id)); |
| |
| /// An object representing the identity of this child. |
| /// |
| /// The [id] needs to be unique among the children that the |
| /// [CustomMultiChildLayout] manages. |
| final Object id; |
| |
| @override |
| void applyParentData(RenderObject renderObject) { |
| assert(renderObject.parentData is MultiChildLayoutParentData); |
| final MultiChildLayoutParentData parentData = renderObject.parentData! as MultiChildLayoutParentData; |
| if (parentData.id != id) { |
| parentData.id = id; |
| final AbstractNode? targetParent = renderObject.parent; |
| if (targetParent is RenderObject) { |
| targetParent.markNeedsLayout(); |
| } |
| } |
| } |
| |
| @override |
| Type get debugTypicalAncestorWidgetClass => CustomMultiChildLayout; |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<Object>('id', id)); |
| } |
| } |
| |
| /// A widget that uses a delegate to size and position multiple children. |
| /// |
| /// The delegate can determine the layout constraints for each child and can |
| /// decide where to position each child. The delegate can also determine the |
| /// size of the parent, but the size of the parent cannot depend on the sizes of |
| /// the children. |
| /// |
| /// [CustomMultiChildLayout] is appropriate when there are complex relationships |
| /// between the size and positioning of multiple widgets. To control the |
| /// layout of a single child, [CustomSingleChildLayout] is more appropriate. For |
| /// simple cases, such as aligning a widget to one or another edge, the [Stack] |
| /// widget is more appropriate. |
| /// |
| /// Each child must be wrapped in a [LayoutId] widget to identify the widget for |
| /// the delegate. |
| /// |
| /// {@tool dartpad} |
| /// This example shows a [CustomMultiChildLayout] widget being used to lay out |
| /// colored blocks from start to finish in a cascade that has some overlap. |
| /// |
| /// It responds to changes in [Directionality] by re-laying out its children. |
| /// |
| /// ** See code in examples/api/lib/widgets/basic/custom_multi_child_layout.0.dart ** |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [MultiChildLayoutDelegate], for details about how to control the layout of |
| /// the children. |
| /// * [CustomSingleChildLayout], which uses a delegate to control the layout of |
| /// a single child. |
| /// * [Stack], which arranges children relative to the edges of the container. |
| /// * [Flow], which provides paint-time control of its children using transform |
| /// matrices. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class CustomMultiChildLayout extends MultiChildRenderObjectWidget { |
| /// Creates a custom multi-child layout. |
| /// |
| /// The [delegate] argument must not be null. |
| const CustomMultiChildLayout({ |
| super.key, |
| required this.delegate, |
| super.children, |
| }); |
| |
| /// The delegate that controls the layout of the children. |
| final MultiChildLayoutDelegate delegate; |
| |
| @override |
| RenderCustomMultiChildLayoutBox createRenderObject(BuildContext context) { |
| return RenderCustomMultiChildLayoutBox(delegate: delegate); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderCustomMultiChildLayoutBox renderObject) { |
| renderObject.delegate = delegate; |
| } |
| } |
| |
| /// A box with a specified size. |
| /// |
| /// If given a child, this widget forces it to have a specific width and/or height. |
| /// These values will be ignored if this widget's parent does not permit them. |
| /// For example, this happens if the parent is the screen (forces the child to |
| /// be the same size as the parent), or another [SizedBox] (forces its child to |
| /// have a specific width and/or height). This can be remedied by wrapping the |
| /// child [SizedBox] in a widget that does permit it to be any size up to the |
| /// size of the parent, such as [Center] or [Align]. |
| /// |
| /// If either the width or height is null, this widget will try to size itself to |
| /// match the child's size in that dimension. If the child's size depends on the |
| /// size of its parent, the height and width must be provided. |
| /// |
| /// If not given a child, [SizedBox] will try to size itself as close to the |
| /// specified height and width as possible given the parent's constraints. If |
| /// [height] or [width] is null or unspecified, it will be treated as zero. |
| /// |
| /// The [SizedBox.expand] constructor can be used to make a [SizedBox] that |
| /// sizes itself to fit the parent. It is equivalent to setting [width] and |
| /// [height] to [double.infinity]. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=EHPu_DzRfqA} |
| /// |
| /// {@tool snippet} |
| /// |
| /// This snippet makes the child widget (a [Card] with some [Text]) have the |
| /// exact size 200x300, parental constraints permitting: |
| /// |
| /// ```dart |
| /// const SizedBox( |
| /// width: 200.0, |
| /// height: 300.0, |
| /// child: Card(child: Text('Hello World!')), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [ConstrainedBox], a more generic version of this class that takes |
| /// arbitrary [BoxConstraints] instead of an explicit width and height. |
| /// * [UnconstrainedBox], a container that tries to let its child draw without |
| /// constraints. |
| /// * [FractionallySizedBox], a widget that sizes its child to a fraction of |
| /// the total available space. |
| /// * [AspectRatio], a widget that attempts to fit within the parent's |
| /// constraints while also sizing its child to match a given aspect ratio. |
| /// * [FittedBox], which sizes and positions its child widget to fit the parent |
| /// according to a given [BoxFit] discipline. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| /// * [Understanding constraints](https://flutter.dev/docs/development/ui/layout/constraints), |
| /// an in-depth article about layout in Flutter. |
| class SizedBox extends SingleChildRenderObjectWidget { |
| /// Creates a fixed size box. The [width] and [height] parameters can be null |
| /// to indicate that the size of the box should not be constrained in |
| /// the corresponding dimension. |
| const SizedBox({ super.key, this.width, this.height, super.child }); |
| |
| /// Creates a box that will become as large as its parent allows. |
| const SizedBox.expand({ super.key, super.child }) |
| : width = double.infinity, |
| height = double.infinity; |
| |
| /// Creates a box that will become as small as its parent allows. |
| const SizedBox.shrink({ super.key, super.child }) |
| : width = 0.0, |
| height = 0.0; |
| |
| /// Creates a box with the specified size. |
| SizedBox.fromSize({ super.key, super.child, Size? size }) |
| : width = size?.width, |
| height = size?.height; |
| |
| /// Creates a box whose [width] and [height] are equal. |
| const SizedBox.square({super.key, super.child, double? dimension}) |
| : width = dimension, |
| height = dimension; |
| |
| /// If non-null, requires the child to have exactly this width. |
| final double? width; |
| |
| /// If non-null, requires the child to have exactly this height. |
| final double? height; |
| |
| @override |
| RenderConstrainedBox createRenderObject(BuildContext context) { |
| return RenderConstrainedBox( |
| additionalConstraints: _additionalConstraints, |
| ); |
| } |
| |
| BoxConstraints get _additionalConstraints { |
| return BoxConstraints.tightFor(width: width, height: height); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderConstrainedBox renderObject) { |
| renderObject.additionalConstraints = _additionalConstraints; |
| } |
| |
| @override |
| String toStringShort() { |
| final String type; |
| if (width == double.infinity && height == double.infinity) { |
| type = '${objectRuntimeType(this, 'SizedBox')}.expand'; |
| } else if (width == 0.0 && height == 0.0) { |
| type = '${objectRuntimeType(this, 'SizedBox')}.shrink'; |
| } else { |
| type = objectRuntimeType(this, 'SizedBox'); |
| } |
| return key == null ? type : '$type-$key'; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| final DiagnosticLevel level; |
| if ((width == double.infinity && height == double.infinity) || |
| (width == 0.0 && height == 0.0)) { |
| level = DiagnosticLevel.hidden; |
| } else { |
| level = DiagnosticLevel.info; |
| } |
| properties.add(DoubleProperty('width', width, defaultValue: null, level: level)); |
| properties.add(DoubleProperty('height', height, defaultValue: null, level: level)); |
| } |
| } |
| |
| /// A widget that imposes additional constraints on its child. |
| /// |
| /// For example, if you wanted [child] to have a minimum height of 50.0 logical |
| /// pixels, you could use `const BoxConstraints(minHeight: 50.0)` as the |
| /// [constraints]. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=o2KveVr7adg} |
| /// |
| /// {@tool snippet} |
| /// |
| /// This snippet makes the child widget (a [Card] with some [Text]) fill the |
| /// parent, by applying [BoxConstraints.expand] constraints: |
| /// |
| /// ```dart |
| /// ConstrainedBox( |
| /// constraints: const BoxConstraints.expand(), |
| /// child: const Card(child: Text('Hello World!')), |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// The same behavior can be obtained using the [SizedBox.expand] widget. |
| /// |
| /// See also: |
| /// |
| /// * [BoxConstraints], the class that describes constraints. |
| /// * [UnconstrainedBox], a container that tries to let its child draw without |
| /// constraints. |
| /// * [SizedBox], which lets you specify tight constraints by explicitly |
| /// specifying the height or width. |
| /// * [FractionallySizedBox], which sizes its child based on a fraction of its |
| /// own size and positions the child according to an [Alignment] value. |
| /// * [AspectRatio], a widget that attempts to fit within the parent's |
| /// constraints while also sizing its child to match a given aspect ratio. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class ConstrainedBox extends SingleChildRenderObjectWidget { |
| /// Creates a widget that imposes additional constraints on its child. |
| /// |
| /// The [constraints] argument must not be null. |
| ConstrainedBox({ |
| super.key, |
| required this.constraints, |
| super.child, |
| }) : assert(constraints.debugAssertIsValid()); |
| |
| /// The additional constraints to impose on the child. |
| final BoxConstraints constraints; |
| |
| @override |
| RenderConstrainedBox createRenderObject(BuildContext context) { |
| return RenderConstrainedBox(additionalConstraints: constraints); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderConstrainedBox renderObject) { |
| renderObject.additionalConstraints = constraints; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<BoxConstraints>('constraints', constraints, showName: false)); |
| } |
| } |
| |
| /// A container widget that applies an arbitrary transform to its constraints, |
| /// and sizes its child using the resulting [BoxConstraints], optionally |
| /// clipping, or treating the overflow as an error. |
| /// |
| /// This container sizes its child using a [BoxConstraints] created by applying |
| /// [constraintsTransform] to its own constraints. This container will then |
| /// attempt to adopt the same size, within the limits of its own constraints. If |
| /// it ends up with a different size, it will align the child based on |
| /// [alignment]. If the container cannot expand enough to accommodate the entire |
| /// child, the child will be clipped if [clipBehavior] is not [Clip.none]. |
| /// |
| /// In debug mode, if [clipBehavior] is [Clip.none] and the child overflows the |
| /// container, a warning will be printed on the console, and black and yellow |
| /// striped areas will appear where the overflow occurs. |
| /// |
| /// When [child] is null, this widget becomes as small as possible and never |
| /// overflows. |
| /// |
| /// This widget can be used to ensure some of [child]'s natural dimensions are |
| /// honored, and get an early warning otherwise during development. For |
| /// instance, if [child] requires a minimum height to fully display its content, |
| /// [constraintsTransform] can be set to [maxHeightUnconstrained], so that if |
| /// the parent [RenderObject] fails to provide enough vertical space, a warning |
| /// will be displayed in debug mode, while still allowing [child] to grow |
| /// vertically: |
| /// |
| /// {@tool snippet} |
| /// In the following snippet, the [Card] is guaranteed to be at least as tall as |
| /// its "natural" height. Unlike [UnconstrainedBox], it will become taller if |
| /// its "natural" height is smaller than 40 px. If the [Container] isn't high |
| /// enough to show the full content of the [Card], in debug mode a warning will |
| /// be given. |
| /// |
| /// ```dart |
| /// Container( |
| /// constraints: const BoxConstraints(minHeight: 40, maxHeight: 100), |
| /// alignment: Alignment.center, |
| /// child: const ConstraintsTransformBox( |
| /// constraintsTransform: ConstraintsTransformBox.maxHeightUnconstrained, |
| /// child: Card(child: Text('Hello World!')), |
| /// ) |
| /// ) |
| /// ``` |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [ConstrainedBox], which renders a box which imposes constraints |
| /// on its child. |
| /// * [OverflowBox], a widget that imposes additional constraints on its child, |
| /// and allows the child to overflow itself. |
| /// * [UnconstrainedBox] which allows its children to render themselves |
| /// unconstrained and expands to fit them. |
| class ConstraintsTransformBox extends SingleChildRenderObjectWidget { |
| /// Creates a widget that uses a function to transform the constraints it |
| /// passes to its child. If the child overflows the parent's constraints, a |
| /// warning will be given in debug mode. |
| /// |
| /// The `debugTransformType` argument adds a debug label to this widget. |
| /// |
| /// The `alignment`, `clipBehavior` and `constraintsTransform` arguments must |
| /// not be null. |
| const ConstraintsTransformBox({ |
| super.key, |
| super.child, |
| this.textDirection, |
| this.alignment = Alignment.center, |
| required this.constraintsTransform, |
| this.clipBehavior = Clip.none, |
| String debugTransformType = '', |
| }) : _debugTransformLabel = debugTransformType; |
| |
| /// A [BoxConstraintsTransform] that always returns its argument as-is (i.e., |
| /// it is an identity function). |
| /// |
| /// The [ConstraintsTransformBox] becomes a proxy widget that has no effect on |
| /// layout if [constraintsTransform] is set to this. |
| static BoxConstraints unmodified(BoxConstraints constraints) => constraints; |
| |
| /// A [BoxConstraintsTransform] that always returns a [BoxConstraints] that |
| /// imposes no constraints on either dimension (i.e. `const BoxConstraints()`). |
| /// |
| /// Setting [constraintsTransform] to this allows [child] to render at its |
| /// "natural" size (equivalent to an [UnconstrainedBox] with `constrainedAxis` |
| /// set to null). |
| static BoxConstraints unconstrained(BoxConstraints constraints) => const BoxConstraints(); |
| |
| /// A [BoxConstraintsTransform] that removes the width constraints from the |
| /// input. |
| /// |
| /// Setting [constraintsTransform] to this allows [child] to render at its |
| /// "natural" width (equivalent to an [UnconstrainedBox] with |
| /// `constrainedAxis` set to [Axis.horizontal]). |
| static BoxConstraints widthUnconstrained(BoxConstraints constraints) => constraints.heightConstraints(); |
| |
| /// A [BoxConstraintsTransform] that removes the height constraints from the |
| /// input. |
| /// |
| /// Setting [constraintsTransform] to this allows [child] to render at its |
| /// "natural" height (equivalent to an [UnconstrainedBox] with |
| /// `constrainedAxis` set to [Axis.vertical]). |
| static BoxConstraints heightUnconstrained(BoxConstraints constraints) => constraints.widthConstraints(); |
| |
| /// A [BoxConstraintsTransform] that removes the `maxHeight` constraint from |
| /// the input. |
| /// |
| /// Setting [constraintsTransform] to this allows [child] to render at its |
| /// "natural" height or the `minHeight` of the incoming [BoxConstraints], |
| /// whichever is larger. |
| static BoxConstraints maxHeightUnconstrained(BoxConstraints constraints) => constraints.copyWith(maxHeight: double.infinity); |
| |
| /// A [BoxConstraintsTransform] that removes the `maxWidth` constraint from |
| /// the input. |
| /// |
| /// Setting [constraintsTransform] to this allows [child] to render at its |
| /// "natural" width or the `minWidth` of the incoming [BoxConstraints], |
| /// whichever is larger. |
| static BoxConstraints maxWidthUnconstrained(BoxConstraints constraints) => constraints.copyWith(maxWidth: double.infinity); |
| |
| /// A [BoxConstraintsTransform] that removes both the `maxWidth` and the |
| /// `maxHeight` constraints from the input. |
| /// |
| /// Setting [constraintsTransform] to this allows [child] to render at least |
| /// its "natural" size, and grow along an axis if the incoming |
| /// [BoxConstraints] has a larger minimum constraint on that axis. |
| static BoxConstraints maxUnconstrained(BoxConstraints constraints) => constraints.copyWith(maxWidth: double.infinity, maxHeight: double.infinity); |
| |
| static final Map<BoxConstraintsTransform, String> _debugKnownTransforms = <BoxConstraintsTransform, String>{ |
| unmodified: 'unmodified', |
| unconstrained: 'unconstrained', |
| widthUnconstrained: 'width constraints removed', |
| heightUnconstrained: 'height constraints removed', |
| maxWidthUnconstrained: 'maxWidth constraint removed', |
| maxHeightUnconstrained: 'maxHeight constraint removed', |
| maxUnconstrained: 'maxWidth & maxHeight constraints removed', |
| }; |
| |
| /// The text direction to use when interpreting the [alignment] if it is an |
| /// [AlignmentDirectional]. |
| /// |
| /// Defaults to null, in which case [Directionality.maybeOf] is used to determine |
| /// the text direction. |
| final TextDirection? textDirection; |
| |
| /// The alignment to use when laying out the child, if it has a different size |
| /// than this widget. |
| /// |
| /// If this is an [AlignmentDirectional], then [textDirection] must not be |
| /// null. |
| /// |
| /// See also: |
| /// |
| /// * [Alignment] for non-[Directionality]-aware alignments. |
| /// * [AlignmentDirectional] for [Directionality]-aware alignments. |
| final AlignmentGeometry alignment; |
| |
| /// {@template flutter.widgets.constraintsTransform} |
| /// The function used to transform the incoming [BoxConstraints], to size |
| /// [child]. |
| /// |
| /// The function must return a [BoxConstraints] that is |
| /// [BoxConstraints.isNormalized]. |
| /// |
| /// See [ConstraintsTransformBox] for predefined common |
| /// [BoxConstraintsTransform]s. |
| /// {@endtemplate} |
| final BoxConstraintsTransform constraintsTransform; |
| |
| /// {@macro flutter.material.Material.clipBehavior} |
| /// |
| /// {@template flutter.widgets.ConstraintsTransformBox.clipBehavior} |
| /// In debug mode, if [clipBehavior] is [Clip.none], and the child overflows |
| /// its constraints, a warning will be printed on the console, and black and |
| /// yellow striped areas will appear where the overflow occurs. For other |
| /// values of [clipBehavior], the contents are clipped accordingly. |
| /// {@endtemplate} |
| /// |
| /// Defaults to [Clip.none]. |
| final Clip clipBehavior; |
| |
| final String _debugTransformLabel; |
| |
| @override |
| RenderConstraintsTransformBox createRenderObject(BuildContext context) { |
| return RenderConstraintsTransformBox( |
| textDirection: textDirection ?? Directionality.maybeOf(context), |
| alignment: alignment, |
| constraintsTransform: constraintsTransform, |
| clipBehavior: clipBehavior, |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, covariant RenderConstraintsTransformBox renderObject) { |
| renderObject |
| ..textDirection = textDirection ?? Directionality.maybeOf(context) |
| ..constraintsTransform = constraintsTransform |
| ..alignment = alignment |
| ..clipBehavior = clipBehavior; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); |
| properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); |
| |
| final String? debugTransformLabel = _debugTransformLabel.isNotEmpty |
| ? _debugTransformLabel |
| : _debugKnownTransforms[constraintsTransform]; |
| |
| if (debugTransformLabel != null) { |
| properties.add(DiagnosticsProperty<String>('constraints transform', debugTransformLabel)); |
| } |
| } |
| } |
| |
| /// A widget that imposes no constraints on its child, allowing it to render |
| /// at its "natural" size. |
| /// |
| /// This allows a child to render at the size it would render if it were alone |
| /// on an infinite canvas with no constraints. This container will then attempt |
| /// to adopt the same size, within the limits of its own constraints. If it ends |
| /// up with a different size, it will align the child based on [alignment]. |
| /// If the box cannot expand enough to accommodate the entire child, the |
| /// child will be clipped. |
| /// |
| /// In debug mode, if the child overflows the container, a warning will be |
| /// printed on the console, and black and yellow striped areas will appear where |
| /// the overflow occurs. |
| /// |
| /// See also: |
| /// |
| /// * [ConstrainedBox], for a box which imposes constraints on its child. |
| /// * [Align], which loosens the constraints given to the child rather than |
| /// removing them entirely. |
| /// * [Container], a convenience widget that combines common painting, |
| /// positioning, and sizing widgets. |
| /// * [OverflowBox], a widget that imposes different constraints on its child |
| /// than it gets from its parent, possibly allowing the child to overflow |
| /// the parent. |
| /// * [ConstraintsTransformBox], a widget that sizes its child using a |
| /// transformed [BoxConstraints], and shows a warning if the child overflows |
| /// in debug mode. |
| class UnconstrainedBox extends StatelessWidget { |
| /// Creates a widget that imposes no constraints on its child, allowing it to |
| /// render at its "natural" size. If the child overflows the parents |
| /// constraints, a warning will be given in debug mode. |
| const UnconstrainedBox({ |
| super.key, |
| this.child, |
| this.textDirection, |
| this.alignment = Alignment.center, |
| this.constrainedAxis, |
| this.clipBehavior = Clip.none, |
| }); |
| |
| /// The text direction to use when interpreting the [alignment] if it is an |
| /// [AlignmentDirectional]. |
| final TextDirection? textDirection; |
| |
| /// The alignment to use when laying out the child. |
| /// |
| /// If this is an [AlignmentDirectional], then [textDirection] must not be |
| /// null. |
| /// |
| /// See also: |
| /// |
| /// * [Alignment] for non-[Directionality]-aware alignments. |
| /// * [AlignmentDirectional] for [Directionality]-aware alignments. |
| final AlignmentGeometry alignment; |
| |
| /// The axis to retain constraints on, if any. |
| /// |
| /// If not set, or set to null (the default), neither axis will retain its |
| /// constraints. If set to [Axis.vertical], then vertical constraints will |
| /// be retained, and if set to [Axis.horizontal], then horizontal constraints |
| /// will be retained. |
| final Axis? constrainedAxis; |
| |
| /// {@macro flutter.material.Material.clipBehavior} |
| /// |
| /// Defaults to [Clip.none]. |
| final Clip clipBehavior; |
| |
| /// The widget below this widget in the tree. |
| /// |
| /// {@macro flutter.widgets.ProxyWidget.child} |
| final Widget? child; |
| |
| BoxConstraintsTransform _axisToTransform(Axis? constrainedAxis) { |
| if (constrainedAxis != null) { |
| switch (constrainedAxis) { |
| case Axis.horizontal: |
| return ConstraintsTransformBox.heightUnconstrained; |
| case Axis.vertical: |
| return ConstraintsTransformBox.widthUnconstrained; |
| } |
| } else { |
| return ConstraintsTransformBox.unconstrained; |
| } |
| } |
| |
| @override |
| Widget build(BuildContext context) { |
| return ConstraintsTransformBox( |
| textDirection: textDirection, |
| alignment: alignment, |
| clipBehavior: clipBehavior, |
| constraintsTransform: _axisToTransform(constrainedAxis), |
| child: child, |
| ); |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); |
| properties.add(EnumProperty<Axis>('constrainedAxis', constrainedAxis, defaultValue: null)); |
| properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); |
| } |
| } |
| |
| /// A widget that sizes its child to a fraction of the total available space. |
| /// For more details about the layout algorithm, see |
| /// [RenderFractionallySizedOverflowBox]. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=PEsY654EGZ0} |
| /// |
| /// {@tool dartpad} |
| /// This sample shows a [FractionallySizedBox] whose one child is 50% of |
| /// the box's size per the width and height factor parameters, and centered |
| /// within that box by the alignment parameter. |
| /// |
| /// ** See code in examples/api/lib/widgets/basic/fractionally_sized_box.0.dart ** |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [Align], which sizes itself based on its child's size and positions |
| /// the child according to an [Alignment] value. |
| /// * [OverflowBox], a widget that imposes different constraints on its child |
| /// than it gets from its parent, possibly allowing the child to overflow the |
| /// parent. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class FractionallySizedBox extends SingleChildRenderObjectWidget { |
| /// Creates a widget that sizes its child to a fraction of the total available space. |
| /// |
| /// If non-null, the [widthFactor] and [heightFactor] arguments must be |
| /// non-negative. |
| const FractionallySizedBox({ |
| super.key, |
| this.alignment = Alignment.center, |
| this.widthFactor, |
| this.heightFactor, |
| super.child, |
| }) : assert(widthFactor == null || widthFactor >= 0.0), |
| assert(heightFactor == null || heightFactor >= 0.0); |
| |
| /// {@template flutter.widgets.basic.fractionallySizedBox.widthFactor} |
| /// If non-null, the fraction of the incoming width given to the child. |
| /// |
| /// If non-null, the child is given a tight width constraint that is the max |
| /// incoming width constraint multiplied by this factor. |
| /// |
| /// If null, the incoming width constraints are passed to the child |
| /// unmodified. |
| /// {@endtemplate} |
| final double? widthFactor; |
| |
| /// {@template flutter.widgets.basic.fractionallySizedBox.heightFactor} |
| /// If non-null, the fraction of the incoming height given to the child. |
| /// |
| /// If non-null, the child is given a tight height constraint that is the max |
| /// incoming height constraint multiplied by this factor. |
| /// |
| /// If null, the incoming height constraints are passed to the child |
| /// unmodified. |
| /// {@endtemplate} |
| final double? heightFactor; |
| |
| /// {@template flutter.widgets.basic.fractionallySizedBox.alignment} |
| /// How to align the child. |
| /// |
| /// The x and y values of the alignment control the horizontal and vertical |
| /// alignment, respectively. An x value of -1.0 means that the left edge of |
| /// the child is aligned with the left edge of the parent whereas an x value |
| /// of 1.0 means that the right edge of the child is aligned with the right |
| /// edge of the parent. Other values interpolate (and extrapolate) linearly. |
| /// For example, a value of 0.0 means that the center of the child is aligned |
| /// with the center of the parent. |
| /// |
| /// Defaults to [Alignment.center]. |
| /// |
| /// See also: |
| /// |
| /// * [Alignment], a class with convenient constants typically used to |
| /// specify an [AlignmentGeometry]. |
| /// * [AlignmentDirectional], like [Alignment] for specifying alignments |
| /// relative to text direction. |
| /// {@endtemplate} |
| final AlignmentGeometry alignment; |
| |
| @override |
| RenderFractionallySizedOverflowBox createRenderObject(BuildContext context) { |
| return RenderFractionallySizedOverflowBox( |
| alignment: alignment, |
| widthFactor: widthFactor, |
| heightFactor: heightFactor, |
| textDirection: Directionality.maybeOf(context), |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderFractionallySizedOverflowBox renderObject) { |
| renderObject |
| ..alignment = alignment |
| ..widthFactor = widthFactor |
| ..heightFactor = heightFactor |
| ..textDirection = Directionality.maybeOf(context); |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); |
| properties.add(DoubleProperty('widthFactor', widthFactor, defaultValue: null)); |
| properties.add(DoubleProperty('heightFactor', heightFactor, defaultValue: null)); |
| } |
| } |
| |
| /// A box that limits its size only when it's unconstrained. |
| /// |
| /// If this widget's maximum width is unconstrained then its child's width is |
| /// limited to [maxWidth]. Similarly, if this widget's maximum height is |
| /// unconstrained then its child's height is limited to [maxHeight]. |
| /// |
| /// This has the effect of giving the child a natural dimension in unbounded |
| /// environments. For example, by providing a [maxHeight] to a widget that |
| /// normally tries to be as big as possible, the widget will normally size |
| /// itself to fit its parent, but when placed in a vertical list, it will take |
| /// on the given height. |
| /// |
| /// This is useful when composing widgets that normally try to match their |
| /// parents' size, so that they behave reasonably in lists (which are |
| /// unbounded). |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=uVki2CIzBTs} |
| /// |
| /// See also: |
| /// |
| /// * [ConstrainedBox], which applies its constraints in all cases, not just |
| /// when the incoming constraints are unbounded. |
| /// * [SizedBox], which lets you specify tight constraints by explicitly |
| /// specifying the height or width. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class LimitedBox extends SingleChildRenderObjectWidget { |
| /// Creates a box that limits its size only when it's unconstrained. |
| /// |
| /// The [maxWidth] and [maxHeight] arguments must not be null and must not be |
| /// negative. |
| const LimitedBox({ |
| super.key, |
| this.maxWidth = double.infinity, |
| this.maxHeight = double.infinity, |
| super.child, |
| }) : assert(maxWidth >= 0.0), |
| assert(maxHeight >= 0.0); |
| |
| /// The maximum width limit to apply in the absence of a |
| /// [BoxConstraints.maxWidth] constraint. |
| final double maxWidth; |
| |
| /// The maximum height limit to apply in the absence of a |
| /// [BoxConstraints.maxHeight] constraint. |
| final double maxHeight; |
| |
| @override |
| RenderLimitedBox createRenderObject(BuildContext context) { |
| return RenderLimitedBox( |
| maxWidth: maxWidth, |
| maxHeight: maxHeight, |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderLimitedBox renderObject) { |
| renderObject |
| ..maxWidth = maxWidth |
| ..maxHeight = maxHeight; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DoubleProperty('maxWidth', maxWidth, defaultValue: double.infinity)); |
| properties.add(DoubleProperty('maxHeight', maxHeight, defaultValue: double.infinity)); |
| } |
| } |
| |
| /// A widget that imposes different constraints on its child than it gets |
| /// from its parent, possibly allowing the child to overflow the parent. |
| /// |
| /// See also: |
| /// |
| /// * [RenderConstrainedOverflowBox] for details about how [OverflowBox] is |
| /// rendered. |
| /// * [SizedOverflowBox], a widget that is a specific size but passes its |
| /// original constraints through to its child, which may then overflow. |
| /// * [ConstrainedBox], a widget that imposes additional constraints on its |
| /// child. |
| /// * [UnconstrainedBox], a container that tries to let its child draw without |
| /// constraints. |
| /// * [SizedBox], a box with a specified size. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class OverflowBox extends SingleChildRenderObjectWidget { |
| /// Creates a widget that lets its child overflow itself. |
| const OverflowBox({ |
| super.key, |
| this.alignment = Alignment.center, |
| this.minWidth, |
| this.maxWidth, |
| this.minHeight, |
| this.maxHeight, |
| super.child, |
| }); |
| |
| /// How to align the child. |
| /// |
| /// The x and y values of the alignment control the horizontal and vertical |
| /// alignment, respectively. An x value of -1.0 means that the left edge of |
| /// the child is aligned with the left edge of the parent whereas an x value |
| /// of 1.0 means that the right edge of the child is aligned with the right |
| /// edge of the parent. Other values interpolate (and extrapolate) linearly. |
| /// For example, a value of 0.0 means that the center of the child is aligned |
| /// with the center of the parent. |
| /// |
| /// Defaults to [Alignment.center]. |
| /// |
| /// See also: |
| /// |
| /// * [Alignment], a class with convenient constants typically used to |
| /// specify an [AlignmentGeometry]. |
| /// * [AlignmentDirectional], like [Alignment] for specifying alignments |
| /// relative to text direction. |
| final AlignmentGeometry alignment; |
| |
| /// The minimum width constraint to give the child. Set this to null (the |
| /// default) to use the constraint from the parent instead. |
| final double? minWidth; |
| |
| /// The maximum width constraint to give the child. Set this to null (the |
| /// default) to use the constraint from the parent instead. |
| final double? maxWidth; |
| |
| /// The minimum height constraint to give the child. Set this to null (the |
| /// default) to use the constraint from the parent instead. |
| final double? minHeight; |
| |
| /// The maximum height constraint to give the child. Set this to null (the |
| /// default) to use the constraint from the parent instead. |
| final double? maxHeight; |
| |
| @override |
| RenderConstrainedOverflowBox createRenderObject(BuildContext context) { |
| return RenderConstrainedOverflowBox( |
| alignment: alignment, |
| minWidth: minWidth, |
| maxWidth: maxWidth, |
| minHeight: minHeight, |
| maxHeight: maxHeight, |
| textDirection: Directionality.maybeOf(context), |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderConstrainedOverflowBox renderObject) { |
| renderObject |
| ..alignment = alignment |
| ..minWidth = minWidth |
| ..maxWidth = maxWidth |
| ..minHeight = minHeight |
| ..maxHeight = maxHeight |
| ..textDirection = Directionality.maybeOf(context); |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); |
| properties.add(DoubleProperty('minWidth', minWidth, defaultValue: null)); |
| properties.add(DoubleProperty('maxWidth', maxWidth, defaultValue: null)); |
| properties.add(DoubleProperty('minHeight', minHeight, defaultValue: null)); |
| properties.add(DoubleProperty('maxHeight', maxHeight, defaultValue: null)); |
| } |
| } |
| |
| /// A widget that is a specific size but passes its original constraints |
| /// through to its child, which may then overflow. |
| /// |
| /// See also: |
| /// |
| /// * [OverflowBox], A widget that imposes different constraints on its child |
| /// than it gets from its parent, possibly allowing the child to overflow the |
| /// parent. |
| /// * [ConstrainedBox], a widget that imposes additional constraints on its |
| /// child. |
| /// * [UnconstrainedBox], a container that tries to let its child draw without |
| /// constraints. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class SizedOverflowBox extends SingleChildRenderObjectWidget { |
| /// Creates a widget of a given size that lets its child overflow. |
| /// |
| /// The [size] argument must not be null. |
| const SizedOverflowBox({ |
| super.key, |
| required this.size, |
| this.alignment = Alignment.center, |
| super.child, |
| }); |
| |
| /// How to align the child. |
| /// |
| /// The x and y values of the alignment control the horizontal and vertical |
| /// alignment, respectively. An x value of -1.0 means that the left edge of |
| /// the child is aligned with the left edge of the parent whereas an x value |
| /// of 1.0 means that the right edge of the child is aligned with the right |
| /// edge of the parent. Other values interpolate (and extrapolate) linearly. |
| /// For example, a value of 0.0 means that the center of the child is aligned |
| /// with the center of the parent. |
| /// |
| /// Defaults to [Alignment.center]. |
| /// |
| /// See also: |
| /// |
| /// * [Alignment], a class with convenient constants typically used to |
| /// specify an [AlignmentGeometry]. |
| /// * [AlignmentDirectional], like [Alignment] for specifying alignments |
| /// relative to text direction. |
| final AlignmentGeometry alignment; |
| |
| /// The size this widget should attempt to be. |
| final Size size; |
| |
| @override |
| RenderSizedOverflowBox createRenderObject(BuildContext context) { |
| return RenderSizedOverflowBox( |
| alignment: alignment, |
| requestedSize: size, |
| textDirection: Directionality.of(context), |
| ); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderSizedOverflowBox renderObject) { |
| renderObject |
| ..alignment = alignment |
| ..requestedSize = size |
| ..textDirection = Directionality.of(context); |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment)); |
| properties.add(DiagnosticsProperty<Size>('size', size, defaultValue: null)); |
| } |
| } |
| |
| /// A widget that lays the child out as if it was in the tree, but without |
| /// painting anything, without making the child available for hit testing, and |
| /// without taking any room in the parent. |
| /// |
| /// Offstage children are still active: they can receive focus and have keyboard |
| /// input directed to them. |
| /// |
| /// Animations continue to run in offstage children, and therefore use battery |
| /// and CPU time, regardless of whether the animations end up being visible. |
| /// |
| /// [Offstage] can be used to measure the dimensions of a widget without |
| /// bringing it on screen (yet). To hide a widget from view while it is not |
| /// needed, prefer removing the widget from the tree entirely rather than |
| /// keeping it alive in an [Offstage] subtree. |
| /// |
| /// {@tool dartpad} |
| /// This example shows a [FlutterLogo] widget when the `_offstage` member field |
| /// is false, and hides it without any room in the parent when it is true. When |
| /// offstage, this app displays a button to get the logo size, which will be |
| /// displayed in a [SnackBar]. |
| /// |
| /// ** See code in examples/api/lib/widgets/basic/offstage.0.dart ** |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [Visibility], which can hide a child more efficiently (albeit less |
| /// subtly). |
| /// * [TickerMode], which can be used to disable animations in a subtree. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class Offstage extends SingleChildRenderObjectWidget { |
| /// Creates a widget that visually hides its child. |
| const Offstage({ super.key, this.offstage = true, super.child }); |
| |
| /// Whether the child is hidden from the rest of the tree. |
| /// |
| /// If true, the child is laid out as if it was in the tree, but without |
| /// painting anything, without making the child available for hit testing, and |
| /// without taking any room in the parent. |
| /// |
| /// Offstage children are still active: they can receive focus and have keyboard |
| /// input directed to them. |
| /// |
| /// Animations continue to run in offstage children, and therefore use battery |
| /// and CPU time, regardless of whether the animations end up being visible. |
| /// |
| /// If false, the child is included in the tree as normal. |
| final bool offstage; |
| |
| @override |
| RenderOffstage createRenderObject(BuildContext context) => RenderOffstage(offstage: offstage); |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderOffstage renderObject) { |
| renderObject.offstage = offstage; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DiagnosticsProperty<bool>('offstage', offstage)); |
| } |
| |
| @override |
| SingleChildRenderObjectElement createElement() => _OffstageElement(this); |
| } |
| |
| class _OffstageElement extends SingleChildRenderObjectElement { |
| _OffstageElement(Offstage super.widget); |
| |
| @override |
| void debugVisitOnstageChildren(ElementVisitor visitor) { |
| if (!(widget as Offstage).offstage) { |
| super.debugVisitOnstageChildren(visitor); |
| } |
| } |
| } |
| |
| /// A widget that attempts to size the child to a specific aspect ratio. |
| /// |
| /// The widget first tries the largest width permitted by the layout |
| /// constraints. The height of the widget is determined by applying the |
| /// given aspect ratio to the width, expressed as a ratio of width to height. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=XcnP3_mO_Ms} |
| /// |
| /// For example, a 16:9 width:height aspect ratio would have a value of |
| /// 16.0/9.0. If the maximum width is infinite, the initial width is determined |
| /// by applying the aspect ratio to the maximum height. |
| /// |
| /// {@tool dartpad} |
| /// This examples shows how AspectRatio sets width when its parent's width |
| /// constraint is infinite. Since its parent's allowed height is a fixed value, |
| /// the actual width is determined via the given AspectRatio. |
| /// |
| /// Since the height is fixed at 100.0 in this example and the aspect ratio is |
| /// set to 16 / 9, the width should then be 100.0 / 9 * 16. |
| /// |
| /// ** See code in examples/api/lib/widgets/basic/aspect_ratio.0.dart ** |
| /// {@end-tool} |
| /// |
| /// Now consider a second example, this time with an aspect ratio of 2.0 and |
| /// layout constraints that require the width to be between 0.0 and 100.0 and |
| /// the height to be between 0.0 and 100.0. We'll select a width of 100.0 (the |
| /// biggest allowed) and a height of 50.0 (to match the aspect ratio). |
| /// |
| /// {@tool dartpad} |
| /// |
| /// |
| /// ** See code in examples/api/lib/widgets/basic/aspect_ratio.1.dart ** |
| /// {@end-tool} |
| /// |
| /// In that same situation, if the aspect ratio is 0.5, we'll also select a |
| /// width of 100.0 (still the biggest allowed) and we'll attempt to use a height |
| /// of 200.0. Unfortunately, that violates the constraints because the child can |
| /// be at most 100.0 pixels tall. The widget will then take that value |
| /// and apply the aspect ratio again to obtain a width of 50.0. That width is |
| /// permitted by the constraints and the child receives a width of 50.0 and a |
| /// height of 100.0. If the width were not permitted, the widget would |
| /// continue iterating through the constraints. If the widget does not |
| /// find a feasible size after consulting each constraint, the widget |
| /// will eventually select a size for the child that meets the layout |
| /// constraints but fails to meet the aspect ratio constraints. |
| /// |
| /// {@tool dartpad} |
| /// |
| /// |
| /// ** See code in examples/api/lib/widgets/basic/aspect_ratio.2.dart ** |
| /// {@end-tool} |
| /// |
| /// See also: |
| /// |
| /// * [Align], a widget that aligns its child within itself and optionally |
| /// sizes itself based on the child's size. |
| /// * [ConstrainedBox], a widget that imposes additional constraints on its |
| /// child. |
| /// * [UnconstrainedBox], a container that tries to let its child draw without |
| /// constraints. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class AspectRatio extends SingleChildRenderObjectWidget { |
| /// Creates a widget with a specific aspect ratio. |
| /// |
| /// The [aspectRatio] argument must be a finite number greater than zero. |
| const AspectRatio({ |
| super.key, |
| required this.aspectRatio, |
| super.child, |
| }) : assert(aspectRatio > 0.0); |
| |
| /// The aspect ratio to attempt to use. |
| /// |
| /// The aspect ratio is expressed as a ratio of width to height. For example, |
| /// a 16:9 width:height aspect ratio would have a value of 16.0/9.0. |
| final double aspectRatio; |
| |
| @override |
| RenderAspectRatio createRenderObject(BuildContext context) => RenderAspectRatio(aspectRatio: aspectRatio); |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderAspectRatio renderObject) { |
| renderObject.aspectRatio = aspectRatio; |
| } |
| |
| @override |
| void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
| super.debugFillProperties(properties); |
| properties.add(DoubleProperty('aspectRatio', aspectRatio)); |
| } |
| } |
| |
| /// A widget that sizes its child to the child's maximum intrinsic width. |
| /// |
| /// This class is useful, for example, when unlimited width is available and |
| /// you would like a child that would otherwise attempt to expand infinitely to |
| /// instead size itself to a more reasonable width. |
| /// |
| /// The constraints that this widget passes to its child will adhere to the |
| /// parent's constraints, so if the constraints are not large enough to satisfy |
| /// the child's maximum intrinsic width, then the child will get less width |
| /// than it otherwise would. Likewise, if the minimum width constraint is |
| /// larger than the child's maximum intrinsic width, the child will be given |
| /// more width than it otherwise would. |
| /// |
| /// If [stepWidth] is non-null, the child's width will be snapped to a multiple |
| /// of the [stepWidth]. Similarly, if [stepHeight] is non-null, the child's |
| /// height will be snapped to a multiple of the [stepHeight]. |
| /// |
| /// This class is relatively expensive, because it adds a speculative layout |
| /// pass before the final layout phase. Avoid using it where possible. In the |
| /// worst case, this widget can result in a layout that is O(N²) in the depth of |
| /// the tree. |
| /// |
| /// See also: |
| /// |
| /// * [Align], a widget that aligns its child within itself. This can be used |
| /// to loosen the constraints passed to the [RenderIntrinsicWidth], |
| /// allowing the [RenderIntrinsicWidth]'s child to be smaller than that of |
| /// its parent. |
| /// * [Row], which when used with [CrossAxisAlignment.stretch] can be used |
| /// to loosen just the width constraints that are passed to the |
| /// [RenderIntrinsicWidth], allowing the [RenderIntrinsicWidth]'s child's |
| /// width to be smaller than that of its parent. |
| /// * [The catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class IntrinsicWidth extends SingleChildRenderObjectWidget { |
| /// Creates a widget that sizes its child to the child's intrinsic width. |
| /// |
| /// This class is relatively expensive. Avoid using it where possible. |
| const IntrinsicWidth({ super.key, this.stepWidth, this.stepHeight, super.child }) |
| : assert(stepWidth == null || stepWidth >= 0.0), |
| assert(stepHeight == null || stepHeight >= 0.0); |
| |
| /// If non-null, force the child's width to be a multiple of this value. |
| /// |
| /// If null or 0.0 the child's width will be the same as its maximum |
| /// intrinsic width. |
| /// |
| /// This value must not be negative. |
| /// |
| /// See also: |
| /// |
| /// * [RenderBox.getMaxIntrinsicWidth], which defines a widget's max |
| /// intrinsic width in general. |
| final double? stepWidth; |
| |
| /// If non-null, force the child's height to be a multiple of this value. |
| /// |
| /// If null or 0.0 the child's height will not be constrained. |
| /// |
| /// This value must not be negative. |
| final double? stepHeight; |
| |
| double? get _stepWidth => stepWidth == 0.0 ? null : stepWidth; |
| double? get _stepHeight => stepHeight == 0.0 ? null : stepHeight; |
| |
| @override |
| RenderIntrinsicWidth createRenderObject(BuildContext context) { |
| return RenderIntrinsicWidth(stepWidth: _stepWidth, stepHeight: _stepHeight); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderIntrinsicWidth renderObject) { |
| renderObject |
| ..stepWidth = _stepWidth |
| ..stepHeight = _stepHeight; |
| } |
| } |
| |
| /// A widget that sizes its child to the child's intrinsic height. |
| /// |
| /// This class is useful, for example, when unlimited height is available and |
| /// you would like a child that would otherwise attempt to expand infinitely to |
| /// instead size itself to a more reasonable height. |
| /// |
| /// The constraints that this widget passes to its child will adhere to the |
| /// parent's constraints, so if the constraints are not large enough to satisfy |
| /// the child's maximum intrinsic height, then the child will get less height |
| /// than it otherwise would. Likewise, if the minimum height constraint is |
| /// larger than the child's maximum intrinsic height, the child will be given |
| /// more height than it otherwise would. |
| /// |
| /// This class is relatively expensive, because it adds a speculative layout |
| /// pass before the final layout phase. Avoid using it where possible. In the |
| /// worst case, this widget can result in a layout that is O(N²) in the depth of |
| /// the tree. |
| /// |
| /// See also: |
| /// |
| /// * [Align], a widget that aligns its child within itself. This can be used |
| /// to loosen the constraints passed to the [RenderIntrinsicHeight], |
| /// allowing the [RenderIntrinsicHeight]'s child to be smaller than that of |
| /// its parent. |
| /// * [Column], which when used with [CrossAxisAlignment.stretch] can be used |
| /// to loosen just the height constraints that are passed to the |
| /// [RenderIntrinsicHeight], allowing the [RenderIntrinsicHeight]'s child's |
| /// height to be smaller than that of its parent. |
| /// * [The catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class IntrinsicHeight extends SingleChildRenderObjectWidget { |
| /// Creates a widget that sizes its child to the child's intrinsic height. |
| /// |
| /// This class is relatively expensive. Avoid using it where possible. |
| const IntrinsicHeight({ super.key, super.child }); |
| |
| @override |
| RenderIntrinsicHeight createRenderObject(BuildContext context) => RenderIntrinsicHeight(); |
| } |
| |
| /// A widget that positions its child according to the child's baseline. |
| /// |
| /// This widget shifts the child down such that the child's baseline (or the |
| /// bottom of the child, if the child has no baseline) is [baseline] |
| /// logical pixels below the top of this box, then sizes this box to |
| /// contain the child. If [baseline] is less than the distance from |
| /// the top of the child to the baseline of the child, then the child |
| /// is top-aligned instead. |
| /// |
| /// {@youtube 560 315 https://www.youtube.com/watch?v=8ZaFk0yvNlI} |
| /// |
| /// See also: |
| /// |
| /// * [Align], a widget that aligns its child within itself and optionally |
| /// sizes itself based on the child's size. |
| /// * [Center], a widget that centers its child within itself. |
| /// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). |
| class Baseline extends SingleChildRenderObjectWidget { |
| /// Creates a widget that positions its child according to the child's baseline. |
| /// |
| /// The [baseline] and [baselineType] arguments must not be null. |
| const Baseline({ |
| super.key, |
| required this.baseline, |
| required this.baselineType, |
| super.child, |
| }); |
| |
| /// The number of logical pixels from the top of this box at which to position |
| /// the child's baseline. |
| final double baseline; |
| |
| /// The type of baseline to use for positioning the child. |
| final TextBaseline baselineType; |
| |
| @override |
| RenderBaseline createRenderObject(BuildContext context) { |
| return RenderBaseline(baseline: baseline, baselineType: baselineType); |
| } |
| |
| @override |
| void updateRenderObject(BuildContext context, RenderBaseline renderObject) { |
| renderObject |
| ..baseline = baseline |
| ..baselineType = baselineType; |
| } |
| } |
| |
| |
| // SLIVERS |
| |
| /// A sliver that contains a single box widget. |
| /// |
| /// Slivers are special-purpose widgets that can be combined using a |
| /// [CustomScrollView] to create custom scroll effects. A [SliverToBoxAdapter] |
| /// is a basic sliver that creates a bridge back to one of the usual box-based |
| /// widgets. |
| /// |
| /// Rather than using multiple [SliverToBoxAdapter] widgets to display multiple |
| /// box widgets in a [CustomScrollView], consider using [SliverList], |
| /// [SliverFixedExtentList], [SliverPrototypeExtentList], or [SliverGrid], |
| /// which are more efficient because they instantiate only those children that |
| /// are actually visible through the scroll view's viewport. |
| /// |
| /// See also: |
| /// |
| /// * [CustomScrollView], which displays a scrollable list of slivers. |
| /// * [SliverList], which displays multiple box widgets in a linear array. |
| /// * [SliverFixedExtentList], which displays multiple box widgets with the |
| /// same main-axis extent in a linear array. |
| /// * [SliverPrototypeExtentList], which displays multiple box widgets with the |
| /// same main-axis extent as a prototype item, in a linear array. |
| /// * [SliverGrid], which displays multiple box widgets in arbitrary positions. |
| class SliverToBoxAdapter extends SingleChildRenderObjectWidget { |
| /// Creates a sliver that contains a single box widget. |
| const SliverToBoxAdapter({ |
| super.key, |
| super.child, |
| }); |
| |
| @override |
| RenderSliverToBoxAdapter createRenderObject(BuildContext context) => RenderSliverToBoxAdapter(); |
| } |
| |
| /// A sliver that applies padding on each side of another sliver. |
| /// |
| /// Slivers are special-purpose widgets that can be combined using a |
| /// [CustomScrollView] to create custom scroll effects. A [SliverPadding] |
| /// is a basic sliver that insets another sliver by applying padding on each |
| /// side. |
| /// |
| /// {@macro flutter.rendering.RenderSliverEdgeInsetsPadding} |
| /// |
| /// See also: |
| /// |
| /// * [CustomScrollView], which displays a scrollable list of slivers. |
| class SliverPadding extends SingleChildRenderObjectWidget { |
| /// Creates a sliver that applies padding on each side of another sliver. |
| /// |
| /// The [padding] argument must not be null. |
| const SliverPadding({ |
| super.key, |
| required this.padding, |
| Widget? sliver, |
| }) : super(child: sliver); |
| |