|  | // 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 'package:flutter/rendering.dart'; | 
|  |  | 
|  | import 'basic.dart'; | 
|  | import 'container.dart'; | 
|  | import 'framework.dart'; | 
|  | import 'text.dart'; | 
|  |  | 
|  | export 'package:flutter/rendering.dart' show RelativeRect; | 
|  |  | 
|  | /// A widget that rebuilds when the given [Listenable] changes value. | 
|  | /// | 
|  | /// {@youtube 560 315 https://www.youtube.com/watch?v=LKKgYpC-EPQ} | 
|  | /// | 
|  | /// [AnimatedWidget] is most commonly used with [Animation] objects, which are | 
|  | /// [Listenable], but it can be used with any [Listenable], including | 
|  | /// [ChangeNotifier] and [ValueNotifier]. | 
|  | /// | 
|  | /// [AnimatedWidget] is most useful for widgets that are otherwise stateless. To | 
|  | /// use [AnimatedWidget], simply subclass it and implement the build function. | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// This code defines a widget called `Spinner` that spins a green square | 
|  | /// continually. It is built with an [AnimatedWidget]. | 
|  | /// | 
|  | /// ** See code in examples/api/lib/widgets/transitions/animated_widget.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// | 
|  | /// For more complex case involving additional state, consider using | 
|  | /// [AnimatedBuilder]. | 
|  | /// | 
|  | /// ## Relationship to [ImplicitlyAnimatedWidget]s | 
|  | /// | 
|  | /// [AnimatedWidget]s (and their subclasses) take an explicit [Listenable] as | 
|  | /// argument, which is usually an [Animation] derived from an | 
|  | /// [AnimationController]. In most cases, the lifecycle of that | 
|  | /// [AnimationController] has to be managed manually by the developer. | 
|  | /// In contrast to that, [ImplicitlyAnimatedWidget]s (and their subclasses) | 
|  | /// automatically manage their own internal [AnimationController] making those | 
|  | /// classes easier to use as no external [Animation] has to be provided by the | 
|  | /// developer. If you only need to set a target value for the animation and | 
|  | /// configure its duration/curve, consider using (a subclass of) | 
|  | /// [ImplicitlyAnimatedWidget]s instead of (a subclass of) this class. | 
|  | /// | 
|  | /// ## Common animated widgets | 
|  | /// | 
|  | /// A number of animated widgets ship with the framework. They are usually named | 
|  | /// `FooTransition`, where `Foo` is the name of the non-animated | 
|  | /// version of that widget. The subclasses of this class should not be confused | 
|  | /// with subclasses of [ImplicitlyAnimatedWidget] (see above), which are usually | 
|  | /// named `AnimatedFoo`. Commonly used animated widgets include: | 
|  | /// | 
|  | ///  * [AnimatedBuilder], which is useful for complex animation use cases and a | 
|  | ///    notable exception to the naming scheme of [AnimatedWidget] subclasses. | 
|  | ///  * [AlignTransition], which is an animated version of [Align]. | 
|  | ///  * [DecoratedBoxTransition], which is an animated version of [DecoratedBox]. | 
|  | ///  * [DefaultTextStyleTransition], which is an animated version of | 
|  | ///    [DefaultTextStyle]. | 
|  | ///  * [PositionedTransition], which is an animated version of [Positioned]. | 
|  | ///  * [RelativePositionedTransition], which is an animated version of | 
|  | ///    [Positioned]. | 
|  | ///  * [RotationTransition], which animates the rotation of a widget. | 
|  | ///  * [ScaleTransition], which animates the scale of a widget. | 
|  | ///  * [SizeTransition], which animates its own size. | 
|  | ///  * [SlideTransition], which animates the position of a widget relative to | 
|  | ///    its normal position. | 
|  | ///  * [FadeTransition], which is an animated version of [Opacity]. | 
|  | ///  * [AnimatedModalBarrier], which is an animated version of [ModalBarrier]. | 
|  | abstract class AnimatedWidget extends StatefulWidget { | 
|  | /// Creates a widget that rebuilds when the given listenable changes. | 
|  | /// | 
|  | /// The [listenable] argument is required. | 
|  | const AnimatedWidget({ | 
|  | super.key, | 
|  | required this.listenable, | 
|  | }) : assert(listenable != null); | 
|  |  | 
|  | /// The [Listenable] to which this widget is listening. | 
|  | /// | 
|  | /// Commonly an [Animation] or a [ChangeNotifier]. | 
|  | final Listenable listenable; | 
|  |  | 
|  | /// Override this method to build widgets that depend on the state of the | 
|  | /// listenable (e.g., the current value of the animation). | 
|  | @protected | 
|  | Widget build(BuildContext context); | 
|  |  | 
|  | /// Subclasses typically do not override this method. | 
|  | @override | 
|  | State<AnimatedWidget> createState() => _AnimatedState(); | 
|  |  | 
|  | @override | 
|  | void debugFillProperties(DiagnosticPropertiesBuilder properties) { | 
|  | super.debugFillProperties(properties); | 
|  | properties.add(DiagnosticsProperty<Listenable>('animation', listenable)); | 
|  | } | 
|  | } | 
|  |  | 
|  | class _AnimatedState extends State<AnimatedWidget> { | 
|  | @override | 
|  | void initState() { | 
|  | super.initState(); | 
|  | widget.listenable.addListener(_handleChange); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void didUpdateWidget(AnimatedWidget oldWidget) { | 
|  | super.didUpdateWidget(oldWidget); | 
|  | if (widget.listenable != oldWidget.listenable) { | 
|  | oldWidget.listenable.removeListener(_handleChange); | 
|  | widget.listenable.addListener(_handleChange); | 
|  | } | 
|  | } | 
|  |  | 
|  | @override | 
|  | void dispose() { | 
|  | widget.listenable.removeListener(_handleChange); | 
|  | super.dispose(); | 
|  | } | 
|  |  | 
|  | void _handleChange() { | 
|  | setState(() { | 
|  | // The listenable's state is our build state, and it changed already. | 
|  | }); | 
|  | } | 
|  |  | 
|  | @override | 
|  | Widget build(BuildContext context) => widget.build(context); | 
|  | } | 
|  |  | 
|  | /// Animates the position of a widget relative to its normal position. | 
|  | /// | 
|  | /// The translation is expressed as an [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. | 
|  | /// | 
|  | /// By default, the offsets are applied in the coordinate system of the canvas | 
|  | /// (so positive x offsets move the child towards the right). If a | 
|  | /// [textDirection] is provided, then the offsets are applied in the reading | 
|  | /// direction, so in right-to-left text, positive x offsets move towards the | 
|  | /// left, and in left-to-right text, positive x offsets move towards the right. | 
|  | /// | 
|  | /// Here's an illustration of the [SlideTransition] widget, with its [position] | 
|  | /// animated by a [CurvedAnimation] set to [Curves.elasticIn]: | 
|  | /// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/slide_transition.mp4} | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// The following code implements the [SlideTransition] as seen in the video | 
|  | /// above: | 
|  | /// | 
|  | /// ** See code in examples/api/lib/widgets/transitions/slide_transition.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [AlignTransition], an animated version of an [Align] that animates its | 
|  | ///    [Align.alignment] property. | 
|  | ///  * [PositionedTransition], a widget that animates its child from a start | 
|  | ///    position to an end position over the lifetime of the animation. | 
|  | ///  * [RelativePositionedTransition], a widget that transitions its child's | 
|  | ///    position based on the value of a rectangle relative to a bounding box. | 
|  | class SlideTransition extends AnimatedWidget { | 
|  | /// Creates a fractional translation transition. | 
|  | /// | 
|  | /// The [position] argument must not be null. | 
|  | const SlideTransition({ | 
|  | super.key, | 
|  | required Animation<Offset> position, | 
|  | this.transformHitTests = true, | 
|  | this.textDirection, | 
|  | this.child, | 
|  | }) : assert(position != null), | 
|  | super(listenable: position); | 
|  |  | 
|  | /// The animation that controls the position of the child. | 
|  | /// | 
|  | /// If the current value of the position animation is `(dx, dy)`, the child | 
|  | /// will be translated horizontally by `width * dx` and vertically by | 
|  | /// `height * dy`, after applying the [textDirection] if available. | 
|  | Animation<Offset> get position => listenable as Animation<Offset>; | 
|  |  | 
|  | /// The direction to use for the x offset described by the [position]. | 
|  | /// | 
|  | /// If [textDirection] is null, the x offset is applied in the coordinate | 
|  | /// system of the canvas (so positive x offsets move the child towards the | 
|  | /// right). | 
|  | /// | 
|  | /// If [textDirection] is [TextDirection.rtl], the x offset is applied in the | 
|  | /// reading direction such that x offsets move the child towards the left. | 
|  | /// | 
|  | /// If [textDirection] is [TextDirection.ltr], the x offset is applied in the | 
|  | /// reading direction such that x offsets move the child towards the right. | 
|  | final TextDirection? textDirection; | 
|  |  | 
|  | /// Whether hit testing should be affected by the slide animation. | 
|  | /// | 
|  | /// If false, hit testing will proceed as if the child was not translated at | 
|  | /// all. Setting this value to false is useful for fast animations where you | 
|  | /// expect the user to commonly interact with the child widget in its final | 
|  | /// location and you want the user to benefit from "muscle memory". | 
|  | final bool transformHitTests; | 
|  |  | 
|  | /// The widget below this widget in the tree. | 
|  | /// | 
|  | /// {@macro flutter.widgets.ProxyWidget.child} | 
|  | final Widget? child; | 
|  |  | 
|  | @override | 
|  | Widget build(BuildContext context) { | 
|  | Offset offset = position.value; | 
|  | if (textDirection == TextDirection.rtl) { | 
|  | offset = Offset(-offset.dx, offset.dy); | 
|  | } | 
|  | return FractionalTranslation( | 
|  | translation: offset, | 
|  | transformHitTests: transformHitTests, | 
|  | child: child, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Animates the scale of a transformed widget. | 
|  | /// | 
|  | /// Here's an illustration of the [ScaleTransition] widget, with it's [alignment] | 
|  | /// animated by a [CurvedAnimation] set to [Curves.fastOutSlowIn]: | 
|  | /// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/scale_transition.mp4} | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// The following code implements the [ScaleTransition] as seen in the video | 
|  | /// above: | 
|  | /// | 
|  | /// ** See code in examples/api/lib/widgets/transitions/scale_transition.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [PositionedTransition], a widget that animates its child from a start | 
|  | ///    position to an end position over the lifetime of the animation. | 
|  | ///  * [RelativePositionedTransition], a widget that transitions its child's | 
|  | ///    position based on the value of a rectangle relative to a bounding box. | 
|  | ///  * [SizeTransition], a widget that animates its own size and clips and | 
|  | ///    aligns its child. | 
|  | class ScaleTransition extends AnimatedWidget { | 
|  | /// Creates a scale transition. | 
|  | /// | 
|  | /// The [scale] argument must not be null. The [alignment] argument defaults | 
|  | /// to [Alignment.center]. | 
|  | const ScaleTransition({ | 
|  | super.key, | 
|  | required Animation<double> scale, | 
|  | this.alignment = Alignment.center, | 
|  | this.filterQuality, | 
|  | this.child, | 
|  | }) : assert(scale != null), | 
|  | super(listenable: scale); | 
|  |  | 
|  | /// The animation that controls the scale of the child. | 
|  | /// | 
|  | /// If the current value of the scale animation is v, the child will be | 
|  | /// painted v times its normal size. | 
|  | Animation<double> get scale => listenable as Animation<double>; | 
|  |  | 
|  | /// The alignment of the origin of the coordinate system in which the scale | 
|  | /// takes place, relative to the size of the box. | 
|  | /// | 
|  | /// For example, to set the origin of the scale to bottom middle, you can use | 
|  | /// an alignment of (0.0, 1.0). | 
|  | final Alignment alignment; | 
|  |  | 
|  | /// The filter quality with which to apply the transform as a bitmap operation. | 
|  | /// | 
|  | /// When the animation is stopped (either in [AnimationStatus.dismissed] or | 
|  | /// [AnimationStatus.completed]), the filter quality argument will be ignored. | 
|  | /// | 
|  | /// {@macro flutter.widgets.Transform.optional.FilterQuality} | 
|  | final FilterQuality? filterQuality; | 
|  |  | 
|  | /// The widget below this widget in the tree. | 
|  | /// | 
|  | /// {@macro flutter.widgets.ProxyWidget.child} | 
|  | final Widget? child; | 
|  |  | 
|  | @override | 
|  | Widget build(BuildContext context) { | 
|  | // The ImageFilter layer created by setting filterQuality will introduce | 
|  | // a saveLayer call. This is usually worthwhile when animating the layer, | 
|  | // but leaving it in the layer tree before the animation has started or after | 
|  | // it has finished significantly hurts performance. | 
|  | final bool useFilterQuality; | 
|  | switch (scale.status) { | 
|  | case AnimationStatus.dismissed: | 
|  | case AnimationStatus.completed: | 
|  | useFilterQuality = false; | 
|  | break; | 
|  | case AnimationStatus.forward: | 
|  | case AnimationStatus.reverse: | 
|  | useFilterQuality = true; | 
|  | break; | 
|  | } | 
|  | return Transform.scale( | 
|  | scale: scale.value, | 
|  | alignment: alignment, | 
|  | filterQuality: useFilterQuality ? filterQuality : null, | 
|  | child: child, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Animates the rotation of a widget. | 
|  | /// | 
|  | /// Here's an illustration of the [RotationTransition] widget, with it's [turns] | 
|  | /// animated by a [CurvedAnimation] set to [Curves.elasticOut]: | 
|  | /// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/rotation_transition.mp4} | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// The following code implements the [RotationTransition] as seen in the video | 
|  | /// above: | 
|  | /// | 
|  | /// ** See code in examples/api/lib/widgets/transitions/rotation_transition.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [ScaleTransition], a widget that animates the scale of a transformed | 
|  | ///    widget. | 
|  | ///  * [SizeTransition], a widget that animates its own size and clips and | 
|  | ///    aligns its child. | 
|  | class RotationTransition extends AnimatedWidget { | 
|  | /// Creates a rotation transition. | 
|  | /// | 
|  | /// The [turns] argument must not be null. | 
|  | const RotationTransition({ | 
|  | super.key, | 
|  | required Animation<double> turns, | 
|  | this.alignment = Alignment.center, | 
|  | this.filterQuality, | 
|  | this.child, | 
|  | }) : assert(turns != null), | 
|  | super(listenable: turns); | 
|  |  | 
|  | /// The animation that controls the rotation of the child. | 
|  | /// | 
|  | /// If the current value of the turns animation is v, the child will be | 
|  | /// rotated v * 2 * pi radians before being painted. | 
|  | Animation<double> get turns => listenable as Animation<double>; | 
|  |  | 
|  | /// The alignment of the origin of the coordinate system around which the | 
|  | /// rotation occurs, relative to the size of the box. | 
|  | /// | 
|  | /// For example, to set the origin of the rotation to top right corner, use | 
|  | /// an alignment of (1.0, -1.0) or use [Alignment.topRight] | 
|  | final Alignment alignment; | 
|  |  | 
|  | /// The filter quality with which to apply the transform as a bitmap operation. | 
|  | /// | 
|  | /// When the animation is stopped (either in [AnimationStatus.dismissed] or | 
|  | /// [AnimationStatus.completed]), the filter quality argument will be ignored. | 
|  | /// | 
|  | /// {@macro flutter.widgets.Transform.optional.FilterQuality} | 
|  | final FilterQuality? filterQuality; | 
|  |  | 
|  | /// The widget below this widget in the tree. | 
|  | /// | 
|  | /// {@macro flutter.widgets.ProxyWidget.child} | 
|  | final Widget? child; | 
|  |  | 
|  | @override | 
|  | Widget build(BuildContext context) { | 
|  | // The ImageFilter layer created by setting filterQuality will introduce | 
|  | // a saveLayer call. This is usually worthwhile when animating the layer, | 
|  | // but leaving it in the layer tree before the animation has started or after | 
|  | // it has finished significantly hurts performance. | 
|  | final bool useFilterQuality; | 
|  | switch (turns.status) { | 
|  | case AnimationStatus.dismissed: | 
|  | case AnimationStatus.completed: | 
|  | useFilterQuality = false; | 
|  | break; | 
|  | case AnimationStatus.forward: | 
|  | case AnimationStatus.reverse: | 
|  | useFilterQuality = true; | 
|  | break; | 
|  | } | 
|  | return Transform.rotate( | 
|  | angle: turns.value * math.pi * 2.0, | 
|  | alignment: alignment, | 
|  | filterQuality: useFilterQuality ? filterQuality : null, | 
|  | child: child, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Animates its own size and clips and aligns its child. | 
|  | /// | 
|  | /// [SizeTransition] acts as a [ClipRect] that animates either its width or its | 
|  | /// height, depending upon the value of [axis]. The alignment of the child along | 
|  | /// the [axis] is specified by the [axisAlignment]. | 
|  | /// | 
|  | /// Like most widgets, [SizeTransition] will conform to the constraints it is | 
|  | /// given, so be sure to put it in a context where it can change size. For | 
|  | /// instance, if you place it into a [Container] with a fixed size, then the | 
|  | /// [SizeTransition] will not be able to change size, and will appear to do | 
|  | /// nothing. | 
|  | /// | 
|  | /// Here's an illustration of the [SizeTransition] widget, with it's [sizeFactor] | 
|  | /// animated by a [CurvedAnimation] set to [Curves.fastOutSlowIn]: | 
|  | /// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/size_transition.mp4} | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// This code defines a widget that uses [SizeTransition] to change the size | 
|  | /// of [FlutterLogo] continually. It is built with a [Scaffold] | 
|  | /// where the internal widget has space to change its size. | 
|  | /// | 
|  | /// ** See code in examples/api/lib/widgets/transitions/size_transition.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [AnimatedCrossFade], for a widget that automatically animates between | 
|  | ///    the sizes of two children, fading between them. | 
|  | ///  * [ScaleTransition], a widget that scales the size of the child instead of | 
|  | ///    clipping it. | 
|  | ///  * [PositionedTransition], a widget that animates its child from a start | 
|  | ///    position to an end position over the lifetime of the animation. | 
|  | ///  * [RelativePositionedTransition], a widget that transitions its child's | 
|  | ///    position based on the value of a rectangle relative to a bounding box. | 
|  | class SizeTransition extends AnimatedWidget { | 
|  | /// Creates a size transition. | 
|  | /// | 
|  | /// The [axis], [sizeFactor], and [axisAlignment] arguments must not be null. | 
|  | /// The [axis] argument defaults to [Axis.vertical]. The [axisAlignment] | 
|  | /// defaults to 0.0, which centers the child along the main axis during the | 
|  | /// transition. | 
|  | const SizeTransition({ | 
|  | super.key, | 
|  | this.axis = Axis.vertical, | 
|  | required Animation<double> sizeFactor, | 
|  | this.axisAlignment = 0.0, | 
|  | this.child, | 
|  | }) : assert(axis != null), | 
|  | assert(sizeFactor != null), | 
|  | assert(axisAlignment != null), | 
|  | super(listenable: sizeFactor); | 
|  |  | 
|  | /// [Axis.horizontal] if [sizeFactor] modifies the width, otherwise | 
|  | /// [Axis.vertical]. | 
|  | final Axis axis; | 
|  |  | 
|  | /// The animation that controls the (clipped) size of the child. | 
|  | /// | 
|  | /// The width or height (depending on the [axis] value) of this widget will be | 
|  | /// its intrinsic width or height multiplied by [sizeFactor]'s value at the | 
|  | /// current point in the animation. | 
|  | /// | 
|  | /// If the value of [sizeFactor] is less than one, the child will be clipped | 
|  | /// in the appropriate axis. | 
|  | Animation<double> get sizeFactor => listenable as Animation<double>; | 
|  |  | 
|  | /// Describes how to align the child along the axis that [sizeFactor] is | 
|  | /// modifying. | 
|  | /// | 
|  | /// A value of -1.0 indicates the top when [axis] is [Axis.vertical], and the | 
|  | /// start when [axis] is [Axis.horizontal]. The start is on the left when the | 
|  | /// text direction in effect is [TextDirection.ltr] and on the right when it | 
|  | /// is [TextDirection.rtl]. | 
|  | /// | 
|  | /// A value of 1.0 indicates the bottom or end, depending upon the [axis]. | 
|  | /// | 
|  | /// A value of 0.0 (the default) indicates the center for either [axis] value. | 
|  | final double axisAlignment; | 
|  |  | 
|  | /// The widget below this widget in the tree. | 
|  | /// | 
|  | /// {@macro flutter.widgets.ProxyWidget.child} | 
|  | final Widget? child; | 
|  |  | 
|  | @override | 
|  | Widget build(BuildContext context) { | 
|  | final AlignmentDirectional alignment; | 
|  | if (axis == Axis.vertical) { | 
|  | alignment = AlignmentDirectional(-1.0, axisAlignment); | 
|  | } else { | 
|  | alignment = AlignmentDirectional(axisAlignment, -1.0); | 
|  | } | 
|  | return ClipRect( | 
|  | child: Align( | 
|  | alignment: alignment, | 
|  | heightFactor: axis == Axis.vertical ? math.max(sizeFactor.value, 0.0) : null, | 
|  | widthFactor: axis == Axis.horizontal ? math.max(sizeFactor.value, 0.0) : null, | 
|  | child: child, | 
|  | ), | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Animates the opacity of a widget. | 
|  | /// | 
|  | /// For a widget that automatically animates between the sizes of two children, | 
|  | /// fading between them, see [AnimatedCrossFade]. | 
|  | /// | 
|  | /// {@youtube 560 315 https://www.youtube.com/watch?v=rLwWVbv3xDQ} | 
|  | /// | 
|  | /// Here's an illustration of the [FadeTransition] widget, with it's [opacity] | 
|  | /// animated by a [CurvedAnimation] set to [Curves.fastOutSlowIn]: | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// The following code implements the [FadeTransition] using | 
|  | /// the Flutter logo: | 
|  | /// | 
|  | /// ** See code in examples/api/lib/widgets/transitions/fade_transition.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [Opacity], which does not animate changes in opacity. | 
|  | ///  * [AnimatedOpacity], which animates changes in opacity without taking an | 
|  | ///    explicit [Animation] argument. | 
|  | class FadeTransition extends SingleChildRenderObjectWidget { | 
|  | /// Creates an opacity transition. | 
|  | /// | 
|  | /// The [opacity] argument must not be null. | 
|  | const FadeTransition({ | 
|  | super.key, | 
|  | required this.opacity, | 
|  | this.alwaysIncludeSemantics = false, | 
|  | super.child, | 
|  | }) : assert(opacity != null); | 
|  |  | 
|  | /// The animation that controls the opacity of the child. | 
|  | /// | 
|  | /// If the current value of the opacity animation is v, the child will be | 
|  | /// painted with an opacity of v. For example, if v is 0.5, the child will be | 
|  | /// blended 50% with its background. Similarly, if v is 0.0, the child will be | 
|  | /// completely transparent. | 
|  | final Animation<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 | 
|  | RenderAnimatedOpacity createRenderObject(BuildContext context) { | 
|  | return RenderAnimatedOpacity( | 
|  | opacity: opacity, | 
|  | alwaysIncludeSemantics: alwaysIncludeSemantics, | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void updateRenderObject(BuildContext context, RenderAnimatedOpacity renderObject) { | 
|  | renderObject | 
|  | ..opacity = opacity | 
|  | ..alwaysIncludeSemantics = alwaysIncludeSemantics; | 
|  | } | 
|  |  | 
|  | @override | 
|  | void debugFillProperties(DiagnosticPropertiesBuilder properties) { | 
|  | super.debugFillProperties(properties); | 
|  | properties.add(DiagnosticsProperty<Animation<double>>('opacity', opacity)); | 
|  | properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics')); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Animates the opacity of a sliver widget. | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// Creates a [CustomScrollView] with a [SliverFixedExtentList] that uses a | 
|  | /// [SliverFadeTransition] to fade the list in and out. | 
|  | /// | 
|  | /// ** See code in examples/api/lib/widgets/transitions/sliver_fade_transition.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// | 
|  | /// Here's an illustration of the [FadeTransition] widget, the [RenderBox] | 
|  | /// equivalent widget, with it's [opacity] animated by a [CurvedAnimation] set | 
|  | /// to [Curves.fastOutSlowIn]: | 
|  | /// | 
|  | /// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/fade_transition.mp4} | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [SliverOpacity], which does not animate changes in opacity. | 
|  | class SliverFadeTransition extends SingleChildRenderObjectWidget { | 
|  | /// Creates an opacity transition. | 
|  | /// | 
|  | /// The [opacity] argument must not be null. | 
|  | const SliverFadeTransition({ | 
|  | super.key, | 
|  | required this.opacity, | 
|  | this.alwaysIncludeSemantics = false, | 
|  | Widget? sliver, | 
|  | }) : assert(opacity != null), | 
|  | super(child: sliver); | 
|  |  | 
|  | /// The animation that controls the opacity of the sliver child. | 
|  | /// | 
|  | /// If the current value of the opacity animation is v, the child will be | 
|  | /// painted with an opacity of v. For example, if v is 0.5, the child will be | 
|  | /// blended 50% with its background. Similarly, if v is 0.0, the child will be | 
|  | /// completely transparent. | 
|  | final Animation<double> opacity; | 
|  |  | 
|  | /// Whether the semantic information of the sliver child is always included. | 
|  | /// | 
|  | /// Defaults to false. | 
|  | /// | 
|  | /// When true, regardless of the opacity settings the sliver child's 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 | 
|  | RenderSliverAnimatedOpacity createRenderObject(BuildContext context) { | 
|  | return RenderSliverAnimatedOpacity( | 
|  | opacity: opacity, | 
|  | alwaysIncludeSemantics: alwaysIncludeSemantics, | 
|  | ); | 
|  | } | 
|  |  | 
|  | @override | 
|  | void updateRenderObject(BuildContext context, RenderSliverAnimatedOpacity renderObject) { | 
|  | renderObject | 
|  | ..opacity = opacity | 
|  | ..alwaysIncludeSemantics = alwaysIncludeSemantics; | 
|  | } | 
|  |  | 
|  | @override | 
|  | void debugFillProperties(DiagnosticPropertiesBuilder properties) { | 
|  | super.debugFillProperties(properties); | 
|  | properties.add(DiagnosticsProperty<Animation<double>>('opacity', opacity)); | 
|  | properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics')); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// An interpolation between two relative rects. | 
|  | /// | 
|  | /// This class specializes the interpolation of [Tween<RelativeRect>] to | 
|  | /// use [RelativeRect.lerp]. | 
|  | /// | 
|  | /// See [Tween] for a discussion on how to use interpolation objects. | 
|  | class RelativeRectTween extends Tween<RelativeRect> { | 
|  | /// Creates a [RelativeRect] tween. | 
|  | /// | 
|  | /// The [begin] and [end] properties may be null; the null value | 
|  | /// is treated as [RelativeRect.fill]. | 
|  | RelativeRectTween({ super.begin, super.end }); | 
|  |  | 
|  | /// Returns the value this variable has at the given animation clock value. | 
|  | @override | 
|  | RelativeRect lerp(double t) => RelativeRect.lerp(begin, end, t)!; | 
|  | } | 
|  |  | 
|  | /// Animated version of [Positioned] which takes a specific | 
|  | /// [Animation<RelativeRect>] to transition the child's position from a start | 
|  | /// position to an end position over the lifetime of the animation. | 
|  | /// | 
|  | /// Only works if it's the child of a [Stack]. | 
|  | /// | 
|  | /// Here's an illustration of the [PositionedTransition] widget, with it's [rect] | 
|  | /// animated by a [CurvedAnimation] set to [Curves.elasticInOut]: | 
|  | /// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/positioned_transition.mp4} | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// The following code implements the [PositionedTransition] as seen in the video | 
|  | /// above: | 
|  | /// | 
|  | /// ** See code in examples/api/lib/widgets/transitions/positioned_transition.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [AnimatedPositioned], which transitions a child's position without | 
|  | ///    taking an explicit [Animation] argument. | 
|  | ///  * [RelativePositionedTransition], a widget that transitions its child's | 
|  | ///    position based on the value of a rectangle relative to a bounding box. | 
|  | ///  * [SlideTransition], a widget that animates the position of a widget | 
|  | ///    relative to its normal position. | 
|  | ///  * [AlignTransition], an animated version of an [Align] that animates its | 
|  | ///    [Align.alignment] property. | 
|  | ///  * [ScaleTransition], a widget that animates the scale of a transformed | 
|  | ///    widget. | 
|  | ///  * [SizeTransition], a widget that animates its own size and clips and | 
|  | ///    aligns its child. | 
|  | class PositionedTransition extends AnimatedWidget { | 
|  | /// Creates a transition for [Positioned]. | 
|  | /// | 
|  | /// The [rect] argument must not be null. | 
|  | const PositionedTransition({ | 
|  | super.key, | 
|  | required Animation<RelativeRect> rect, | 
|  | required this.child, | 
|  | }) : assert(rect != null), | 
|  | super(listenable: rect); | 
|  |  | 
|  | /// The animation that controls the child's size and position. | 
|  | Animation<RelativeRect> get rect => listenable as Animation<RelativeRect>; | 
|  |  | 
|  | /// The widget below this widget in the tree. | 
|  | /// | 
|  | /// {@macro flutter.widgets.ProxyWidget.child} | 
|  | final Widget child; | 
|  |  | 
|  | @override | 
|  | Widget build(BuildContext context) { | 
|  | return Positioned.fromRelativeRect( | 
|  | rect: rect.value, | 
|  | child: child, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Animated version of [Positioned] which transitions the child's position | 
|  | /// based on the value of [rect] relative to a bounding box with the | 
|  | /// specified [size]. | 
|  | /// | 
|  | /// Only works if it's the child of a [Stack]. | 
|  | /// | 
|  | /// Here's an illustration of the [RelativePositionedTransition] widget, with it's [rect] | 
|  | /// animated by a [CurvedAnimation] set to [Curves.elasticInOut]: | 
|  | /// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/relative_positioned_transition.mp4} | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// The following code implements the [RelativePositionedTransition] as seen in the video | 
|  | /// above: | 
|  | /// | 
|  | /// ** See code in examples/api/lib/widgets/transitions/relative_positioned_transition.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [PositionedTransition], a widget that animates its child from a start | 
|  | ///    position to an end position over the lifetime of the animation. | 
|  | ///  * [AlignTransition], an animated version of an [Align] that animates its | 
|  | ///    [Align.alignment] property. | 
|  | ///  * [ScaleTransition], a widget that animates the scale of a transformed | 
|  | ///    widget. | 
|  | ///  * [SizeTransition], a widget that animates its own size and clips and | 
|  | ///    aligns its child. | 
|  | ///  * [SlideTransition], a widget that animates the position of a widget | 
|  | ///    relative to its normal position. | 
|  | class RelativePositionedTransition extends AnimatedWidget { | 
|  | /// Create an animated version of [Positioned]. | 
|  | /// | 
|  | /// Each frame, the [Positioned] widget will be configured to represent the | 
|  | /// current value of the [rect] argument assuming that the stack has the given | 
|  | /// [size]. Both [rect] and [size] must not be null. | 
|  | const RelativePositionedTransition({ | 
|  | super.key, | 
|  | required Animation<Rect?> rect, | 
|  | required this.size, | 
|  | required this.child, | 
|  | }) : assert(rect != null), | 
|  | assert(size != null), | 
|  | assert(child != null), | 
|  | super(listenable: rect); | 
|  |  | 
|  | /// The animation that controls the child's size and position. | 
|  | /// | 
|  | /// If the animation returns a null [Rect], the rect is assumed to be [Rect.zero]. | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [size], which gets the size of the box that the [Positioned] widget's | 
|  | ///    offsets are relative to. | 
|  | Animation<Rect?> get rect => listenable as Animation<Rect?>; | 
|  |  | 
|  | /// The [Positioned] widget's offsets are relative to a box of this | 
|  | /// size whose origin is 0,0. | 
|  | final Size size; | 
|  |  | 
|  | /// The widget below this widget in the tree. | 
|  | /// | 
|  | /// {@macro flutter.widgets.ProxyWidget.child} | 
|  | final Widget child; | 
|  |  | 
|  | @override | 
|  | Widget build(BuildContext context) { | 
|  | final RelativeRect offsets = RelativeRect.fromSize(rect.value ?? Rect.zero, size); | 
|  | return Positioned( | 
|  | top: offsets.top, | 
|  | right: offsets.right, | 
|  | bottom: offsets.bottom, | 
|  | left: offsets.left, | 
|  | child: child, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Animated version of a [DecoratedBox] that animates the different properties | 
|  | /// of its [Decoration]. | 
|  | /// | 
|  | /// Here's an illustration of the [DecoratedBoxTransition] widget, with it's | 
|  | /// [decoration] animated by a [CurvedAnimation] set to [Curves.decelerate]: | 
|  | /// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/decorated_box_transition.mp4} | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// The following code implements the [DecoratedBoxTransition] as seen in the video | 
|  | /// above: | 
|  | /// | 
|  | /// ** See code in examples/api/lib/widgets/transitions/decorated_box_transition.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [DecoratedBox], which also draws a [Decoration] but is not animated. | 
|  | ///  * [AnimatedContainer], a more full-featured container that also animates on | 
|  | ///    decoration using an internal animation. | 
|  | class DecoratedBoxTransition extends AnimatedWidget { | 
|  | /// Creates an animated [DecoratedBox] whose [Decoration] animation updates | 
|  | /// the widget. | 
|  | /// | 
|  | /// The [decoration] and [position] must not be null. | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [DecoratedBox.new] | 
|  | const DecoratedBoxTransition({ | 
|  | super.key, | 
|  | required this.decoration, | 
|  | this.position = DecorationPosition.background, | 
|  | required this.child, | 
|  | }) : assert(decoration != null), | 
|  | assert(child != null), | 
|  | super(listenable: decoration); | 
|  |  | 
|  | /// Animation of the decoration to paint. | 
|  | /// | 
|  | /// Can be created using a [DecorationTween] interpolating typically between | 
|  | /// two [BoxDecoration]. | 
|  | final Animation<Decoration> decoration; | 
|  |  | 
|  | /// Whether to paint the box decoration behind or in front of the child. | 
|  | final DecorationPosition position; | 
|  |  | 
|  | /// The widget below this widget in the tree. | 
|  | /// | 
|  | /// {@macro flutter.widgets.ProxyWidget.child} | 
|  | final Widget child; | 
|  |  | 
|  | @override | 
|  | Widget build(BuildContext context) { | 
|  | return DecoratedBox( | 
|  | decoration: decoration.value, | 
|  | position: position, | 
|  | child: child, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Animated version of an [Align] that animates its [Align.alignment] property. | 
|  | /// | 
|  | /// Here's an illustration of the [DecoratedBoxTransition] widget, with it's | 
|  | /// [DecoratedBoxTransition.decoration] animated by a [CurvedAnimation] set to | 
|  | /// [Curves.decelerate]: | 
|  | /// | 
|  | /// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/align_transition.mp4} | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// The following code implements the [AlignTransition] as seen in the video | 
|  | /// above: | 
|  | /// | 
|  | /// ** See code in examples/api/lib/widgets/transitions/align_transition.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [AnimatedAlign], which animates changes to the [alignment] without | 
|  | ///    taking an explicit [Animation] argument. | 
|  | ///  * [PositionedTransition], a widget that animates its child from a start | 
|  | ///    position to an end position over the lifetime of the animation. | 
|  | ///  * [RelativePositionedTransition], a widget that transitions its child's | 
|  | ///    position based on the value of a rectangle relative to a bounding box. | 
|  | ///  * [SizeTransition], a widget that animates its own size and clips and | 
|  | ///    aligns its child. | 
|  | ///  * [SlideTransition], a widget that animates the position of a widget | 
|  | ///    relative to its normal position. | 
|  | class AlignTransition extends AnimatedWidget { | 
|  | /// Creates an animated [Align] whose [AlignmentGeometry] animation updates | 
|  | /// the widget. | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [Align.new]. | 
|  | const AlignTransition({ | 
|  | super.key, | 
|  | required Animation<AlignmentGeometry> alignment, | 
|  | required this.child, | 
|  | this.widthFactor, | 
|  | this.heightFactor, | 
|  | }) : assert(alignment != null), | 
|  | assert(child != null), | 
|  | super(listenable: alignment); | 
|  |  | 
|  | /// The animation that controls the child's alignment. | 
|  | Animation<AlignmentGeometry> get alignment => listenable as Animation<AlignmentGeometry>; | 
|  |  | 
|  | /// If non-null, the child's width factor, see [Align.widthFactor]. | 
|  | final double? widthFactor; | 
|  |  | 
|  | /// If non-null, the child's height factor, see [Align.heightFactor]. | 
|  | final double? heightFactor; | 
|  |  | 
|  | /// The widget below this widget in the tree. | 
|  | /// | 
|  | /// {@macro flutter.widgets.ProxyWidget.child} | 
|  | final Widget child; | 
|  |  | 
|  | @override | 
|  | Widget build(BuildContext context) { | 
|  | return Align( | 
|  | alignment: alignment.value, | 
|  | widthFactor: widthFactor, | 
|  | heightFactor: heightFactor, | 
|  | child: child, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Animated version of a [DefaultTextStyle] that animates the different properties | 
|  | /// of its [TextStyle]. | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// The following code implements the [DefaultTextStyleTransition] that shows | 
|  | /// a transition between thick blue font and thin red font. | 
|  | /// | 
|  | /// ** See code in examples/api/lib/widgets/transitions/default_text_style_transition.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [AnimatedDefaultTextStyle], which animates changes in text style without | 
|  | ///    taking an explicit [Animation] argument. | 
|  | ///  * [DefaultTextStyle], which also defines a [TextStyle] for its descendants | 
|  | ///    but is not animated. | 
|  | class DefaultTextStyleTransition extends AnimatedWidget { | 
|  | /// Creates an animated [DefaultTextStyle] whose [TextStyle] animation updates | 
|  | /// the widget. | 
|  | const DefaultTextStyleTransition({ | 
|  | super.key, | 
|  | required Animation<TextStyle> style, | 
|  | required this.child, | 
|  | this.textAlign, | 
|  | this.softWrap = true, | 
|  | this.overflow = TextOverflow.clip, | 
|  | this.maxLines, | 
|  | }) : assert(style != null), | 
|  | assert(child != null), | 
|  | super(listenable: style); | 
|  |  | 
|  | /// The animation that controls the descendants' text style. | 
|  | Animation<TextStyle> get style => listenable as Animation<TextStyle>; | 
|  |  | 
|  | /// How the text should be aligned horizontally. | 
|  | final TextAlign? textAlign; | 
|  |  | 
|  | /// Whether the text should break at soft line breaks. | 
|  | /// | 
|  | /// See [DefaultTextStyle.softWrap] for more details. | 
|  | final bool softWrap; | 
|  |  | 
|  | /// How visual overflow should be handled. | 
|  | /// | 
|  | final TextOverflow overflow; | 
|  |  | 
|  | /// An optional maximum number of lines for the text to span, wrapping if necessary. | 
|  | /// | 
|  | /// See [DefaultTextStyle.maxLines] for more details. | 
|  | final int? maxLines; | 
|  |  | 
|  | /// The widget below this widget in the tree. | 
|  | /// | 
|  | /// {@macro flutter.widgets.ProxyWidget.child} | 
|  | final Widget child; | 
|  |  | 
|  | @override | 
|  | Widget build(BuildContext context) { | 
|  | return DefaultTextStyle( | 
|  | style: style.value, | 
|  | textAlign: textAlign, | 
|  | softWrap: softWrap, | 
|  | overflow: overflow, | 
|  | maxLines: maxLines, | 
|  | child: child, | 
|  | ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// A general-purpose widget for building animations. | 
|  | /// | 
|  | /// AnimatedBuilder is useful for more complex widgets that wish to include | 
|  | /// an animation as part of a larger build function. To use AnimatedBuilder, | 
|  | /// simply construct the widget and pass it a builder function. | 
|  | /// | 
|  | /// For simple cases without additional state, consider using | 
|  | /// [AnimatedWidget]. | 
|  | /// | 
|  | /// {@youtube 560 315 https://www.youtube.com/watch?v=N-RiyZlv8v8} | 
|  | /// | 
|  | /// ## Performance optimizations | 
|  | /// | 
|  | /// If your [builder] function contains a subtree that does not depend on the | 
|  | /// animation, it's more efficient to build that subtree once instead of | 
|  | /// rebuilding it on every animation tick. | 
|  | /// | 
|  | /// If you pass the pre-built subtree as the [child] parameter, the | 
|  | /// [AnimatedBuilder] will pass it back to your builder function so that you | 
|  | /// can incorporate it into your build. | 
|  | /// | 
|  | /// Using this pre-built child is entirely optional, but can improve | 
|  | /// performance significantly in some cases and is therefore a good practice. | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// This code defines a widget that spins a green square continually. It is | 
|  | /// built with an [AnimatedBuilder] and makes use of the [child] feature to | 
|  | /// avoid having to rebuild the [Container] each time. | 
|  | /// | 
|  | /// ** See code in examples/api/lib/widgets/transitions/animated_builder.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// | 
|  | /// {@template flutter.flutter.animatedbuilder_changenotifier.rebuild} | 
|  | /// ## Improve rebuilds performance using AnimatedBuilder | 
|  | /// | 
|  | /// Despite the name, [AnimatedBuilder] is not limited to [Animation]s. Any subtype | 
|  | /// of [Listenable] (such as [ChangeNotifier] and [ValueNotifier]) can be used with | 
|  | /// an [AnimatedBuilder] to rebuild only certain parts of a widget when the | 
|  | /// [Listenable] notifies its listeners. This technique is a performance improvement | 
|  | /// that allows rebuilding only specific widgets leaving others untouched. | 
|  | /// | 
|  | /// {@tool dartpad} | 
|  | /// The following example implements a simple counter that utilizes an | 
|  | /// [AnimatedBuilder] to limit rebuilds to only the [Text] widget. The current count | 
|  | /// is stored in a [ValueNotifier], which rebuilds the [AnimatedBuilder]'s contents | 
|  | /// when its value is changed. | 
|  | /// | 
|  | /// ** See code in examples/api/lib/foundation/change_notifier/change_notifier.0.dart ** | 
|  | /// {@end-tool} | 
|  | /// {@endtemplate} | 
|  | /// | 
|  | /// See also: | 
|  | /// | 
|  | ///  * [TweenAnimationBuilder], which animates a property to a target value | 
|  | ///    without requiring manual management of an [AnimationController]. | 
|  | class AnimatedBuilder extends AnimatedWidget { | 
|  | /// Creates an animated builder. | 
|  | /// | 
|  | /// The [animation] and [builder] arguments must not be null. | 
|  | const AnimatedBuilder({ | 
|  | super.key, | 
|  | required Listenable animation, | 
|  | required this.builder, | 
|  | this.child, | 
|  | }) : assert(animation != null), | 
|  | assert(builder != null), | 
|  | super(listenable: animation); | 
|  |  | 
|  | /// Called every time the animation changes value. | 
|  | final TransitionBuilder builder; | 
|  |  | 
|  | /// The child widget to pass to the [builder]. | 
|  | /// | 
|  | /// If a [builder] callback's return value contains a subtree that does not | 
|  | /// depend on the animation, it's more efficient to build that subtree once | 
|  | /// instead of rebuilding it on every animation tick. | 
|  | /// | 
|  | /// If the pre-built subtree is passed as the [child] parameter, the | 
|  | /// [AnimatedBuilder] will pass it back to the [builder] function so that it | 
|  | /// can be incorporated into the build. | 
|  | /// | 
|  | /// Using this pre-built child is entirely optional, but can improve | 
|  | /// performance significantly in some cases and is therefore a good practice. | 
|  | final Widget? child; | 
|  |  | 
|  | @override | 
|  | Widget build(BuildContext context) { | 
|  | return builder(context, child); | 
|  | } | 
|  | } |