1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// @docImport 'package:flutter/material.dart';
6///
7/// @docImport 'animated_cross_fade.dart';
8/// @docImport 'animated_size.dart';
9/// @docImport 'animated_switcher.dart';
10/// @docImport 'scroll_view.dart';
11/// @docImport 'sliver.dart';
12/// @docImport 'tween_animation_builder.dart';
13library;
14
15import 'dart:ui' as ui show TextHeightBehavior;
16
17import 'package:flutter/foundation.dart';
18import 'package:flutter/rendering.dart';
19import 'package:vector_math/vector_math_64.dart';
20
21import 'basic.dart';
22import 'container.dart';
23import 'debug.dart';
24import 'framework.dart';
25import 'text.dart';
26import 'ticker_provider.dart';
27import 'transitions.dart';
28
29// Examples can assume:
30// class MyWidget extends ImplicitlyAnimatedWidget {
31// const MyWidget({super.key, this.targetColor = Colors.black}) : super(duration: const Duration(seconds: 1));
32// final Color targetColor;
33// @override
34// ImplicitlyAnimatedWidgetState createState() => throw UnimplementedError(); // ignore: no_logic_in_create_state
35// }
36// void setState(VoidCallback fn) { }
37
38/// An interpolation between two [BoxConstraints].
39///
40/// This class specializes the interpolation of [Tween<BoxConstraints>] to use
41/// [BoxConstraints.lerp].
42///
43/// See [Tween] for a discussion on how to use interpolation objects.
44class BoxConstraintsTween extends Tween<BoxConstraints> {
45 /// Creates a [BoxConstraints] tween.
46 ///
47 /// The [begin] and [end] properties may be null; the null value
48 /// is treated as a tight constraint of zero size.
49 BoxConstraintsTween({ super.begin, super.end });
50
51 /// Returns the value this variable has at the given animation clock value.
52 @override
53 BoxConstraints lerp(double t) => BoxConstraints.lerp(begin, end, t)!;
54}
55
56/// An interpolation between two [Decoration]s.
57///
58/// This class specializes the interpolation of [Tween<BoxConstraints>] to use
59/// [Decoration.lerp].
60///
61/// For [ShapeDecoration]s which know how to [ShapeDecoration.lerpTo] or
62/// [ShapeDecoration.lerpFrom] each other, this will produce a smooth
63/// interpolation between decorations.
64///
65/// See also:
66///
67/// * [Tween] for a discussion on how to use interpolation objects.
68/// * [ShapeDecoration], [RoundedRectangleBorder], [CircleBorder], and
69/// [StadiumBorder] for examples of shape borders that can be smoothly
70/// interpolated.
71/// * [BoxBorder] for a border that can only be smoothly interpolated between other
72/// [BoxBorder]s.
73class DecorationTween extends Tween<Decoration> {
74 /// Creates a decoration tween.
75 ///
76 /// The [begin] and [end] properties may be null. If both are null, then the
77 /// result is always null. If [end] is not null, then its lerping logic is
78 /// used (via [Decoration.lerpTo]). Otherwise, [begin]'s lerping logic is used
79 /// (via [Decoration.lerpFrom]).
80 DecorationTween({ super.begin, super.end });
81
82 /// Returns the value this variable has at the given animation clock value.
83 @override
84 Decoration lerp(double t) => Decoration.lerp(begin, end, t)!;
85}
86
87/// An interpolation between two [EdgeInsets]s.
88///
89/// This class specializes the interpolation of [Tween<EdgeInsets>] to use
90/// [EdgeInsets.lerp].
91///
92/// See [Tween] for a discussion on how to use interpolation objects.
93///
94/// See also:
95///
96/// * [EdgeInsetsGeometryTween], which interpolates between two
97/// [EdgeInsetsGeometry] objects.
98class EdgeInsetsTween extends Tween<EdgeInsets> {
99 /// Creates an [EdgeInsets] tween.
100 ///
101 /// The [begin] and [end] properties may be null; the null value
102 /// is treated as an [EdgeInsets] with no inset.
103 EdgeInsetsTween({ super.begin, super.end });
104
105 /// Returns the value this variable has at the given animation clock value.
106 @override
107 EdgeInsets lerp(double t) => EdgeInsets.lerp(begin, end, t)!;
108}
109
110/// An interpolation between two [EdgeInsetsGeometry]s.
111///
112/// This class specializes the interpolation of [Tween<EdgeInsetsGeometry>] to
113/// use [EdgeInsetsGeometry.lerp].
114///
115/// See [Tween] for a discussion on how to use interpolation objects.
116///
117/// See also:
118///
119/// * [EdgeInsetsTween], which interpolates between two [EdgeInsets] objects.
120class EdgeInsetsGeometryTween extends Tween<EdgeInsetsGeometry> {
121 /// Creates an [EdgeInsetsGeometry] tween.
122 ///
123 /// The [begin] and [end] properties may be null; the null value
124 /// is treated as an [EdgeInsetsGeometry] with no inset.
125 EdgeInsetsGeometryTween({ super.begin, super.end });
126
127 /// Returns the value this variable has at the given animation clock value.
128 @override
129 EdgeInsetsGeometry lerp(double t) => EdgeInsetsGeometry.lerp(begin, end, t)!;
130}
131
132/// An interpolation between two [BorderRadius]s.
133///
134/// This class specializes the interpolation of [Tween<BorderRadius>] to use
135/// [BorderRadius.lerp].
136///
137/// See [Tween] for a discussion on how to use interpolation objects.
138class BorderRadiusTween extends Tween<BorderRadius?> {
139 /// Creates a [BorderRadius] tween.
140 ///
141 /// The [begin] and [end] properties may be null; the null value
142 /// is treated as a right angle (no radius).
143 BorderRadiusTween({ super.begin, super.end });
144
145 /// Returns the value this variable has at the given animation clock value.
146 @override
147 BorderRadius? lerp(double t) => BorderRadius.lerp(begin, end, t);
148}
149
150/// An interpolation between two [Border]s.
151///
152/// This class specializes the interpolation of [Tween<Border>] to use
153/// [Border.lerp].
154///
155/// See [Tween] for a discussion on how to use interpolation objects.
156class BorderTween extends Tween<Border?> {
157 /// Creates a [Border] tween.
158 ///
159 /// The [begin] and [end] properties may be null; the null value
160 /// is treated as having no border.
161 BorderTween({ super.begin, super.end });
162
163 /// Returns the value this variable has at the given animation clock value.
164 @override
165 Border? lerp(double t) => Border.lerp(begin, end, t);
166}
167
168/// An interpolation between two [Matrix4]s.
169///
170/// This class specializes the interpolation of [Tween<Matrix4>] to be
171/// appropriate for transformation matrices.
172///
173/// Currently this class works only for translations.
174///
175/// See [Tween] for a discussion on how to use interpolation objects.
176class Matrix4Tween extends Tween<Matrix4> {
177 /// Creates a [Matrix4] tween.
178 ///
179 /// The [begin] and [end] properties must be non-null before the tween is
180 /// first used, but the arguments can be null if the values are going to be
181 /// filled in later.
182 Matrix4Tween({ super.begin, super.end });
183
184 @override
185 Matrix4 lerp(double t) {
186 assert(begin != null);
187 assert(end != null);
188 final Vector3 beginTranslation = Vector3.zero();
189 final Vector3 endTranslation = Vector3.zero();
190 final Quaternion beginRotation = Quaternion.identity();
191 final Quaternion endRotation = Quaternion.identity();
192 final Vector3 beginScale = Vector3.zero();
193 final Vector3 endScale = Vector3.zero();
194 begin!.decompose(beginTranslation, beginRotation, beginScale);
195 end!.decompose(endTranslation, endRotation, endScale);
196 final Vector3 lerpTranslation =
197 beginTranslation * (1.0 - t) + endTranslation * t;
198 // TODO(alangardner): Implement lerp for constant rotation
199 final Quaternion lerpRotation =
200 (beginRotation.scaled(1.0 - t) + endRotation.scaled(t)).normalized();
201 final Vector3 lerpScale = beginScale * (1.0 - t) + endScale * t;
202 return Matrix4.compose(lerpTranslation, lerpRotation, lerpScale);
203 }
204}
205
206/// An interpolation between two [TextStyle]s.
207///
208/// This class specializes the interpolation of [Tween<TextStyle>] to use
209/// [TextStyle.lerp].
210///
211/// This will not work well if the styles don't set the same fields.
212///
213/// See [Tween] for a discussion on how to use interpolation objects.
214class TextStyleTween extends Tween<TextStyle> {
215 /// Creates a text style tween.
216 ///
217 /// The [begin] and [end] properties must be non-null before the tween is
218 /// first used, but the arguments can be null if the values are going to be
219 /// filled in later.
220 TextStyleTween({ super.begin, super.end });
221
222 /// Returns the value this variable has at the given animation clock value.
223 @override
224 TextStyle lerp(double t) => TextStyle.lerp(begin, end, t)!;
225}
226
227/// An abstract class for building widgets that animate changes to their
228/// properties.
229///
230/// Widgets of this type will not animate when they are first added to the
231/// widget tree. Rather, when they are rebuilt with different values, they will
232/// respond to those _changes_ by animating the changes over a specified
233/// [duration].
234///
235/// Which properties are animated is left up to the subclass. Subclasses' [State]s
236/// must extend [ImplicitlyAnimatedWidgetState] and provide a way to visit the
237/// relevant fields to animate.
238///
239/// ## Relationship to [AnimatedWidget]s
240///
241/// [ImplicitlyAnimatedWidget]s (and their subclasses) automatically animate
242/// changes in their properties whenever they change. For this,
243/// they create and manage their own internal [AnimationController]s to power
244/// the animation. While these widgets are simple to use and don't require you
245/// to manually manage the lifecycle of an [AnimationController], they
246/// are also somewhat limited: Besides the target value for the animated
247/// property, developers can only choose a [duration] and [curve] for the
248/// animation. If you require more control over the animation (e.g. you want
249/// to stop it somewhere in the middle), consider using an
250/// [AnimatedWidget] or one of its subclasses. These widgets take an [Animation]
251/// as an argument to power the animation. This gives the developer full control
252/// over the animation at the cost of requiring you to manually manage the
253/// underlying [AnimationController].
254///
255/// ## Common implicitly animated widgets
256///
257/// A number of implicitly animated widgets ship with the framework. They are
258/// usually named `AnimatedFoo`, where `Foo` is the name of the non-animated
259/// version of that widget. Commonly used implicitly animated widgets include:
260///
261/// * [TweenAnimationBuilder], which animates any property expressed by
262/// a [Tween] to a specified target value.
263/// * [AnimatedAlign], which is an implicitly animated version of [Align].
264/// * [AnimatedContainer], which is an implicitly animated version of
265/// [Container].
266/// * [AnimatedDefaultTextStyle], which is an implicitly animated version of
267/// [DefaultTextStyle].
268/// * [AnimatedScale], which is an implicitly animated version of [Transform.scale].
269/// * [AnimatedRotation], which is an implicitly animated version of [Transform.rotate].
270/// * [AnimatedSlide], which implicitly animates the position of a widget relative to its normal position.
271/// * [AnimatedOpacity], which is an implicitly animated version of [Opacity].
272/// * [AnimatedPadding], which is an implicitly animated version of [Padding].
273/// * [AnimatedPhysicalModel], which is an implicitly animated version of
274/// [PhysicalModel].
275/// * [AnimatedPositioned], which is an implicitly animated version of
276/// [Positioned].
277/// * [AnimatedPositionedDirectional], which is an implicitly animated version
278/// of [PositionedDirectional].
279/// * [AnimatedTheme], which is an implicitly animated version of [Theme].
280/// * [AnimatedCrossFade], which cross-fades between two given children and
281/// animates itself between their sizes.
282/// * [AnimatedSize], which automatically transitions its size over a given
283/// duration.
284/// * [AnimatedSwitcher], which fades from one widget to another.
285abstract class ImplicitlyAnimatedWidget extends StatefulWidget {
286 /// Initializes fields for subclasses.
287 const ImplicitlyAnimatedWidget({
288 super.key,
289 this.curve = Curves.linear,
290 required this.duration,
291 this.onEnd,
292 });
293
294 /// The curve to apply when animating the parameters of this container.
295 final Curve curve;
296
297 /// The duration over which to animate the parameters of this container.
298 final Duration duration;
299
300 /// Called every time an animation completes.
301 ///
302 /// This can be useful to trigger additional actions (e.g. another animation)
303 /// at the end of the current animation.
304 final VoidCallback? onEnd;
305
306 @override
307 ImplicitlyAnimatedWidgetState<ImplicitlyAnimatedWidget> createState();
308
309 @override
310 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
311 super.debugFillProperties(properties);
312 properties.add(IntProperty('duration', duration.inMilliseconds, unit: 'ms'));
313 }
314}
315
316/// Signature for a [Tween] factory.
317///
318/// This is the type of one of the arguments of [TweenVisitor], the signature
319/// used by [AnimatedWidgetBaseState.forEachTween].
320///
321/// Instances of this function are expected to take a value and return a tween
322/// beginning at that value.
323typedef TweenConstructor<T extends Object> = Tween<T> Function(T targetValue);
324
325/// Signature for callbacks passed to [ImplicitlyAnimatedWidgetState.forEachTween].
326///
327/// {@template flutter.widgets.TweenVisitor.arguments}
328/// The `tween` argument should contain the current tween value. This will
329/// initially be null when the state is first initialized.
330///
331/// The `targetValue` argument should contain the value toward which the state
332/// is animating. For instance, if the state is animating its widget's
333/// opacity value, then this argument should contain the widget's current
334/// opacity value.
335///
336/// The `constructor` argument should contain a function that takes a value
337/// (the widget's value being animated) and returns a tween beginning at that
338/// value.
339///
340/// {@endtemplate}
341///
342/// `forEachTween()` is expected to update its tween value to the return value
343/// of this visitor.
344///
345/// The `<T>` parameter specifies the type of value that's being animated.
346typedef TweenVisitor<T extends Object> = Tween<T>? Function(Tween<T>? tween, T targetValue, TweenConstructor<T> constructor);
347
348/// A base class for the `State` of widgets with implicit animations.
349///
350/// [ImplicitlyAnimatedWidgetState] requires that subclasses respond to the
351/// animation themselves. If you would like `setState()` to be called
352/// automatically as the animation changes, use [AnimatedWidgetBaseState].
353///
354/// Properties that subclasses choose to animate are represented by [Tween]
355/// instances. Subclasses must implement the [forEachTween] method to allow
356/// [ImplicitlyAnimatedWidgetState] to iterate through the widget's fields and
357/// animate them.
358abstract class ImplicitlyAnimatedWidgetState<T extends ImplicitlyAnimatedWidget> extends State<T> with SingleTickerProviderStateMixin<T> {
359 /// The animation controller driving this widget's implicit animations.
360 @protected
361 AnimationController get controller => _controller;
362 late final AnimationController _controller = AnimationController(
363 duration: widget.duration,
364 debugLabel: kDebugMode ? widget.toStringShort() : null,
365 vsync: this,
366 );
367
368 /// The animation driving this widget's implicit animations.
369 Animation<double> get animation => _animation;
370 late CurvedAnimation _animation = _createCurve();
371
372 @override
373 void initState() {
374 super.initState();
375 _controller.addStatusListener((AnimationStatus status) {
376 if (status.isCompleted) {
377 widget.onEnd?.call();
378 }
379 });
380 _constructTweens();
381 didUpdateTweens();
382 }
383
384 @override
385 void didUpdateWidget(T oldWidget) {
386 super.didUpdateWidget(oldWidget);
387 if (widget.curve != oldWidget.curve) {
388 _animation.dispose();
389 _animation = _createCurve();
390 }
391 _controller.duration = widget.duration;
392 if (_constructTweens()) {
393 forEachTween((Tween<dynamic>? tween, dynamic targetValue, TweenConstructor<dynamic> constructor) {
394 _updateTween(tween, targetValue);
395 return tween;
396 });
397 _controller
398 ..value = 0.0
399 ..forward();
400 didUpdateTweens();
401 }
402 }
403
404 CurvedAnimation _createCurve() {
405 return CurvedAnimation(parent: _controller, curve: widget.curve);
406 }
407
408 @override
409 void dispose() {
410 _animation.dispose();
411 _controller.dispose();
412 super.dispose();
413 }
414
415 bool _shouldAnimateTween(Tween<dynamic> tween, dynamic targetValue) {
416 return targetValue != (tween.end ?? tween.begin);
417 }
418
419 void _updateTween(Tween<dynamic>? tween, dynamic targetValue) {
420 if (tween == null) {
421 return;
422 }
423 tween
424 ..begin = tween.evaluate(_animation)
425 ..end = targetValue;
426 }
427
428 bool _constructTweens() {
429 bool shouldStartAnimation = false;
430 forEachTween((Tween<dynamic>? tween, dynamic targetValue, TweenConstructor<dynamic> constructor) {
431 if (targetValue != null) {
432 tween ??= constructor(targetValue);
433 if (_shouldAnimateTween(tween, targetValue)) {
434 shouldStartAnimation = true;
435 } else {
436 tween.end ??= tween.begin;
437 }
438 } else {
439 tween = null;
440 }
441 return tween;
442 });
443 return shouldStartAnimation;
444 }
445
446 /// Visits each tween controlled by this state with the specified `visitor`
447 /// function.
448 ///
449 /// ### Subclass responsibility
450 ///
451 /// Properties to be animated are represented by [Tween] member variables in
452 /// the state. For each such tween, [forEachTween] implementations are
453 /// expected to call `visitor` with the appropriate arguments and store the
454 /// result back into the member variable. The arguments to `visitor` are as
455 /// follows:
456 ///
457 /// {@macro flutter.widgets.TweenVisitor.arguments}
458 ///
459 /// ### When this method will be called
460 ///
461 /// [forEachTween] is initially called during [initState]. It is expected that
462 /// the visitor's `tween` argument will be set to null, causing the visitor to
463 /// call its `constructor` argument to construct the tween for the first time.
464 /// The resulting tween will have its `begin` value set to the target value
465 /// and will have its `end` value set to null. The animation will not be
466 /// started.
467 ///
468 /// When this state's [widget] is updated (thus triggering the
469 /// [didUpdateWidget] method to be called), [forEachTween] will be called
470 /// again to check if the target value has changed. If the target value has
471 /// changed, signaling that the [animation] should start, then the visitor
472 /// will update the tween's `start` and `end` values accordingly, and the
473 /// animation will be started.
474 ///
475 /// ### Other member variables
476 ///
477 /// Subclasses that contain properties based on tweens created by
478 /// [forEachTween] should override [didUpdateTweens] to update those
479 /// properties. Dependent properties should not be updated within
480 /// [forEachTween].
481 ///
482 /// {@tool snippet}
483 ///
484 /// This sample implements an implicitly animated widget's `State`.
485 /// The widget animates between colors whenever `widget.targetColor`
486 /// changes.
487 ///
488 /// ```dart
489 /// class MyWidgetState extends AnimatedWidgetBaseState<MyWidget> {
490 /// ColorTween? _colorTween;
491 ///
492 /// @override
493 /// Widget build(BuildContext context) {
494 /// return Text(
495 /// 'Hello World',
496 /// // Computes the value of the text color at any given time.
497 /// style: TextStyle(color: _colorTween?.evaluate(animation)),
498 /// );
499 /// }
500 ///
501 /// @override
502 /// void forEachTween(TweenVisitor<dynamic> visitor) {
503 /// // Update the tween using the provided visitor function.
504 /// _colorTween = visitor(
505 /// // The latest tween value. Can be `null`.
506 /// _colorTween,
507 /// // The color value toward which we are animating.
508 /// widget.targetColor,
509 /// // A function that takes a color value and returns a tween
510 /// // beginning at that value.
511 /// (dynamic value) => ColorTween(begin: value as Color?),
512 /// ) as ColorTween?;
513 ///
514 /// // We could have more tweens than one by using the visitor
515 /// // multiple times.
516 /// }
517 /// }
518 /// ```
519 /// {@end-tool}
520 @protected
521 void forEachTween(TweenVisitor<dynamic> visitor);
522
523 /// Optional hook for subclasses that runs after all tweens have been updated
524 /// via [forEachTween].
525 ///
526 /// Any properties that depend upon tweens created by [forEachTween] should be
527 /// updated within [didUpdateTweens], not within [forEachTween].
528 ///
529 /// This method will be called both:
530 ///
531 /// 1. After the tweens are _initially_ constructed (by
532 /// the `constructor` argument to the [TweenVisitor] that's passed to
533 /// [forEachTween]). In this case, the tweens are likely to contain only
534 /// a [Tween.begin] value and not a [Tween.end].
535 ///
536 /// 2. When the state's [widget] is updated, and one or more of the tweens
537 /// visited by [forEachTween] specifies a target value that's different
538 /// than the widget's current value, thus signaling that the [animation]
539 /// should run. In this case, the [Tween.begin] value for each tween will
540 /// an evaluation of the tween against the current [animation], and the
541 /// [Tween.end] value for each tween will be the target value.
542 @protected
543 void didUpdateTweens() { }
544}
545
546/// A base class for widgets with implicit animations that need to rebuild their
547/// widget tree as the animation runs.
548///
549/// This class calls [build] each frame that the animation ticks. For a
550/// variant that does not rebuild each frame, consider subclassing
551/// [ImplicitlyAnimatedWidgetState] directly.
552///
553/// Subclasses must implement the [forEachTween] method to allow
554/// [AnimatedWidgetBaseState] to iterate through the subclasses' widget's fields
555/// and animate them.
556abstract class AnimatedWidgetBaseState<T extends ImplicitlyAnimatedWidget> extends ImplicitlyAnimatedWidgetState<T> {
557 @override
558 void initState() {
559 super.initState();
560 controller.addListener(_handleAnimationChanged);
561 }
562
563 void _handleAnimationChanged() {
564 setState(() { /* The animation ticked. Rebuild with new animation value */ });
565 }
566}
567
568/// Animated version of [Container] that gradually changes its values over a period of time.
569///
570/// The [AnimatedContainer] will automatically animate between the old and
571/// new values of properties when they change using the provided curve and
572/// duration. Properties that are null are not animated. Its child and
573/// descendants are not animated.
574///
575/// This class is useful for generating simple implicit transitions between
576/// different parameters to [Container] with its internal [AnimationController].
577/// For more complex animations, you'll likely want to use a subclass of
578/// [AnimatedWidget] such as the [DecoratedBoxTransition] or use your own
579/// [AnimationController].
580///
581/// {@youtube 560 315 https://www.youtube.com/watch?v=yI-8QHpGIP4}
582///
583/// {@tool dartpad}
584/// The following example (depicted above) transitions an AnimatedContainer
585/// between two states. It adjusts the `height`, `width`, `color`, and
586/// [alignment] properties when tapped.
587///
588/// ** See code in examples/api/lib/widgets/implicit_animations/animated_container.0.dart **
589/// {@end-tool}
590///
591/// See also:
592///
593/// * [AnimatedPadding], which is a subset of this widget that only
594/// supports animating the [padding].
595/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/).
596/// * [AnimatedPositioned], which, as a child of a [Stack], automatically
597/// transitions its child's position over a given duration whenever the given
598/// position changes.
599/// * [AnimatedAlign], which automatically transitions its child's
600/// position over a given duration whenever the given [AnimatedAlign.alignment] changes.
601/// * [AnimatedSwitcher], which switches out a child for a new one with a customizable transition.
602/// * [AnimatedCrossFade], which fades between two children and interpolates their sizes.
603class AnimatedContainer extends ImplicitlyAnimatedWidget {
604 /// Creates a container that animates its parameters implicitly.
605 AnimatedContainer({
606 super.key,
607 this.alignment,
608 this.padding,
609 Color? color,
610 Decoration? decoration,
611 this.foregroundDecoration,
612 double? width,
613 double? height,
614 BoxConstraints? constraints,
615 this.margin,
616 this.transform,
617 this.transformAlignment,
618 this.child,
619 this.clipBehavior = Clip.none,
620 super.curve,
621 required super.duration,
622 super.onEnd,
623 }) : assert(margin == null || margin.isNonNegative),
624 assert(padding == null || padding.isNonNegative),
625 assert(decoration == null || decoration.debugAssertIsValid()),
626 assert(constraints == null || constraints.debugAssertIsValid()),
627 assert(color == null || decoration == null,
628 'Cannot provide both a color and a decoration\n'
629 'The color argument is just a shorthand for "decoration: BoxDecoration(color: color)".',
630 ),
631 decoration = decoration ?? (color != null ? BoxDecoration(color: color) : null),
632 constraints =
633 (width != null || height != null)
634 ? constraints?.tighten(width: width, height: height)
635 ?? BoxConstraints.tightFor(width: width, height: height)
636 : constraints;
637
638 /// The [child] contained by the container.
639 ///
640 /// If null, and if the [constraints] are unbounded or also null, the
641 /// container will expand to fill all available space in its parent, unless
642 /// the parent provides unbounded constraints, in which case the container
643 /// will attempt to be as small as possible.
644 ///
645 /// {@macro flutter.widgets.ProxyWidget.child}
646 final Widget? child;
647
648 /// Align the [child] within the container.
649 ///
650 /// If non-null, the container will expand to fill its parent and position its
651 /// child within itself according to the given value. If the incoming
652 /// constraints are unbounded, then the child will be shrink-wrapped instead.
653 ///
654 /// Ignored if [child] is null.
655 ///
656 /// See also:
657 ///
658 /// * [Alignment], a class with convenient constants typically used to
659 /// specify an [AlignmentGeometry].
660 /// * [AlignmentDirectional], like [Alignment] for specifying alignments
661 /// relative to text direction.
662 final AlignmentGeometry? alignment;
663
664 /// Empty space to inscribe inside the [decoration]. The [child], if any, is
665 /// placed inside this padding.
666 final EdgeInsetsGeometry? padding;
667
668 /// The decoration to paint behind the [child].
669 ///
670 /// A shorthand for specifying just a solid color is available in the
671 /// constructor: set the `color` argument instead of the `decoration`
672 /// argument.
673 final Decoration? decoration;
674
675 /// The decoration to paint in front of the child.
676 final Decoration? foregroundDecoration;
677
678 /// Additional constraints to apply to the child.
679 ///
680 /// The constructor `width` and `height` arguments are combined with the
681 /// `constraints` argument to set this property.
682 ///
683 /// The [padding] goes inside the constraints.
684 final BoxConstraints? constraints;
685
686 /// Empty space to surround the [decoration] and [child].
687 final EdgeInsetsGeometry? margin;
688
689 /// The transformation matrix to apply before painting the container.
690 final Matrix4? transform;
691
692 /// The alignment of the origin, relative to the size of the container, if [transform] is specified.
693 ///
694 /// When [transform] is null, the value of this property is ignored.
695 ///
696 /// See also:
697 ///
698 /// * [Transform.alignment], which is set by this property.
699 final AlignmentGeometry? transformAlignment;
700
701 /// The clip behavior when [AnimatedContainer.decoration] is not null.
702 ///
703 /// Defaults to [Clip.none]. Must be [Clip.none] if [decoration] is null.
704 ///
705 /// Unlike other properties of [AnimatedContainer], changes to this property
706 /// apply immediately and have no animation.
707 ///
708 /// If a clip is to be applied, the [Decoration.getClipPath] method
709 /// for the provided decoration must return a clip path. (This is not
710 /// supported by all decorations; the default implementation of that
711 /// method throws an [UnsupportedError].)
712 final Clip clipBehavior;
713
714 @override
715 AnimatedWidgetBaseState<AnimatedContainer> createState() => _AnimatedContainerState();
716
717 @override
718 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
719 super.debugFillProperties(properties);
720 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, showName: false, defaultValue: null));
721 properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
722 properties.add(DiagnosticsProperty<Decoration>('bg', decoration, defaultValue: null));
723 properties.add(DiagnosticsProperty<Decoration>('fg', foregroundDecoration, defaultValue: null));
724 properties.add(DiagnosticsProperty<BoxConstraints>('constraints', constraints, defaultValue: null, showName: false));
725 properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('margin', margin, defaultValue: null));
726 properties.add(ObjectFlagProperty<Matrix4>.has('transform', transform));
727 properties.add(DiagnosticsProperty<AlignmentGeometry>('transformAlignment', transformAlignment, defaultValue: null));
728 properties.add(DiagnosticsProperty<Clip>('clipBehavior', clipBehavior));
729 }
730}
731
732class _AnimatedContainerState extends AnimatedWidgetBaseState<AnimatedContainer> {
733 AlignmentGeometryTween? _alignment;
734 EdgeInsetsGeometryTween? _padding;
735 DecorationTween? _decoration;
736 DecorationTween? _foregroundDecoration;
737 BoxConstraintsTween? _constraints;
738 EdgeInsetsGeometryTween? _margin;
739 Matrix4Tween? _transform;
740 AlignmentGeometryTween? _transformAlignment;
741
742 @override
743 void forEachTween(TweenVisitor<dynamic> visitor) {
744 _alignment = visitor(_alignment, widget.alignment, (dynamic value) => AlignmentGeometryTween(begin: value as AlignmentGeometry)) as AlignmentGeometryTween?;
745 _padding = visitor(_padding, widget.padding, (dynamic value) => EdgeInsetsGeometryTween(begin: value as EdgeInsetsGeometry)) as EdgeInsetsGeometryTween?;
746 _decoration = visitor(_decoration, widget.decoration, (dynamic value) => DecorationTween(begin: value as Decoration)) as DecorationTween?;
747 _foregroundDecoration = visitor(_foregroundDecoration, widget.foregroundDecoration, (dynamic value) => DecorationTween(begin: value as Decoration)) as DecorationTween?;
748 _constraints = visitor(_constraints, widget.constraints, (dynamic value) => BoxConstraintsTween(begin: value as BoxConstraints)) as BoxConstraintsTween?;
749 _margin = visitor(_margin, widget.margin, (dynamic value) => EdgeInsetsGeometryTween(begin: value as EdgeInsetsGeometry)) as EdgeInsetsGeometryTween?;
750 _transform = visitor(_transform, widget.transform, (dynamic value) => Matrix4Tween(begin: value as Matrix4)) as Matrix4Tween?;
751 _transformAlignment = visitor(_transformAlignment, widget.transformAlignment, (dynamic value) => AlignmentGeometryTween(begin: value as AlignmentGeometry)) as AlignmentGeometryTween?;
752 }
753
754 @override
755 Widget build(BuildContext context) {
756 final Animation<double> animation = this.animation;
757 return Container(
758 alignment: _alignment?.evaluate(animation),
759 padding: _padding?.evaluate(animation),
760 decoration: _decoration?.evaluate(animation),
761 foregroundDecoration: _foregroundDecoration?.evaluate(animation),
762 constraints: _constraints?.evaluate(animation),
763 margin: _margin?.evaluate(animation),
764 transform: _transform?.evaluate(animation),
765 transformAlignment: _transformAlignment?.evaluate(animation),
766 clipBehavior: widget.clipBehavior,
767 child: widget.child,
768 );
769 }
770
771 @override
772 void debugFillProperties(DiagnosticPropertiesBuilder description) {
773 super.debugFillProperties(description);
774 description.add(DiagnosticsProperty<AlignmentGeometryTween>('alignment', _alignment, showName: false, defaultValue: null));
775 description.add(DiagnosticsProperty<EdgeInsetsGeometryTween>('padding', _padding, defaultValue: null));
776 description.add(DiagnosticsProperty<DecorationTween>('bg', _decoration, defaultValue: null));
777 description.add(DiagnosticsProperty<DecorationTween>('fg', _foregroundDecoration, defaultValue: null));
778 description.add(DiagnosticsProperty<BoxConstraintsTween>('constraints', _constraints, showName: false, defaultValue: null));
779 description.add(DiagnosticsProperty<EdgeInsetsGeometryTween>('margin', _margin, defaultValue: null));
780 description.add(ObjectFlagProperty<Matrix4Tween>.has('transform', _transform));
781 description.add(DiagnosticsProperty<AlignmentGeometryTween>('transformAlignment', _transformAlignment, defaultValue: null));
782 }
783}
784
785/// Animated version of [Padding] which automatically transitions the
786/// indentation over a given duration whenever the given inset changes.
787///
788/// {@youtube 560 315 https://www.youtube.com/watch?v=PY2m0fhGNz4}
789///
790/// Here's an illustration of what using this widget looks like, using a [curve]
791/// of [Curves.fastOutSlowIn].
792/// {@animation 250 266 https://flutter.github.io/assets-for-api-docs/assets/widgets/animated_padding.mp4}
793///
794/// {@tool dartpad}
795/// The following code implements the [AnimatedPadding] widget, using a [curve] of
796/// [Curves.easeInOut].
797///
798/// ** See code in examples/api/lib/widgets/implicit_animations/animated_padding.0.dart **
799/// {@end-tool}
800///
801/// See also:
802///
803/// * [AnimatedContainer], which can transition more values at once.
804/// * [AnimatedAlign], which automatically transitions its child's
805/// position over a given duration whenever the given
806/// [AnimatedAlign.alignment] changes.
807class AnimatedPadding extends ImplicitlyAnimatedWidget {
808 /// Creates a widget that insets its child by a value that animates
809 /// implicitly.
810 AnimatedPadding({
811 super.key,
812 required this.padding,
813 this.child,
814 super.curve,
815 required super.duration,
816 super.onEnd,
817 }) : assert(padding.isNonNegative);
818
819 /// The amount of space by which to inset the child.
820 final EdgeInsetsGeometry padding;
821
822 /// The widget below this widget in the tree.
823 ///
824 /// {@macro flutter.widgets.ProxyWidget.child}
825 final Widget? child;
826
827 @override
828 AnimatedWidgetBaseState<AnimatedPadding> createState() => _AnimatedPaddingState();
829
830 @override
831 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
832 super.debugFillProperties(properties);
833 properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding));
834 }
835}
836
837class _AnimatedPaddingState extends AnimatedWidgetBaseState<AnimatedPadding> {
838 EdgeInsetsGeometryTween? _padding;
839
840 @override
841 void forEachTween(TweenVisitor<dynamic> visitor) {
842 _padding = visitor(_padding, widget.padding, (dynamic value) => EdgeInsetsGeometryTween(begin: value as EdgeInsetsGeometry)) as EdgeInsetsGeometryTween?;
843 }
844
845 @override
846 Widget build(BuildContext context) {
847 return Padding(
848 padding: _padding!
849 .evaluate(animation)
850 .clamp(EdgeInsets.zero, EdgeInsetsGeometry.infinity),
851 child: widget.child,
852 );
853 }
854
855 @override
856 void debugFillProperties(DiagnosticPropertiesBuilder description) {
857 super.debugFillProperties(description);
858 description.add(DiagnosticsProperty<EdgeInsetsGeometryTween>('padding', _padding, defaultValue: null));
859 }
860}
861
862/// Animated version of [Align] which automatically transitions the child's
863/// position over a given duration whenever the given [alignment] changes.
864///
865/// Here's an illustration of what this can look like, using a [curve] of
866/// [Curves.fastOutSlowIn].
867/// {@animation 250 266 https://flutter.github.io/assets-for-api-docs/assets/widgets/animated_align.mp4}
868///
869/// For the animation, you can choose a [curve] as well as a [duration] and the
870/// widget will automatically animate to the new target [alignment]. If you require
871/// more control over the animation (e.g. if you want to stop it mid-animation),
872/// consider using an [AlignTransition] instead, which takes a provided
873/// [Animation] as argument. While that allows you to fine-tune the animation,
874/// it also requires more development overhead as you have to manually manage
875/// the lifecycle of the underlying [AnimationController].
876///
877/// {@tool dartpad}
878/// The following code implements the [AnimatedAlign] widget, using a [curve] of
879/// [Curves.fastOutSlowIn].
880///
881/// ** See code in examples/api/lib/widgets/implicit_animations/animated_align.0.dart **
882/// {@end-tool}
883///
884/// See also:
885///
886/// * [AnimatedContainer], which can transition more values at once.
887/// * [AnimatedPadding], which can animate the padding instead of the
888/// alignment.
889/// * [AnimatedSlide], which can animate the translation of child by a given offset relative to its size.
890/// * [AnimatedPositioned], which, as a child of a [Stack], automatically
891/// transitions its child's position over a given duration whenever the given
892/// position changes.
893class AnimatedAlign extends ImplicitlyAnimatedWidget {
894 /// Creates a widget that positions its child by an alignment that animates
895 /// implicitly.
896 const AnimatedAlign({
897 super.key,
898 required this.alignment,
899 this.child,
900 this.heightFactor,
901 this.widthFactor,
902 super.curve,
903 required super.duration,
904 super.onEnd,
905 }) : assert(widthFactor == null || widthFactor >= 0.0),
906 assert(heightFactor == null || heightFactor >= 0.0);
907
908 /// How to align the child.
909 ///
910 /// The x and y values of the [Alignment] control the horizontal and vertical
911 /// alignment, respectively. An x value of -1.0 means that the left edge of
912 /// the child is aligned with the left edge of the parent whereas an x value
913 /// of 1.0 means that the right edge of the child is aligned with the right
914 /// edge of the parent. Other values interpolate (and extrapolate) linearly.
915 /// For example, a value of 0.0 means that the center of the child is aligned
916 /// with the center of the parent.
917 ///
918 /// See also:
919 ///
920 /// * [Alignment], which has more details and some convenience constants for
921 /// common positions.
922 /// * [AlignmentDirectional], which has a horizontal coordinate orientation
923 /// that depends on the [TextDirection].
924 final AlignmentGeometry alignment;
925
926 /// The widget below this widget in the tree.
927 ///
928 /// {@macro flutter.widgets.ProxyWidget.child}
929 final Widget? child;
930
931 /// If non-null, sets its height to the child's height multiplied by this factor.
932 ///
933 /// Must be greater than or equal to 0.0, defaults to null.
934 final double? heightFactor;
935
936 /// If non-null, sets its width to the child's width multiplied by this factor.
937 ///
938 /// Must be greater than or equal to 0.0, defaults to null.
939 final double? widthFactor;
940
941 @override
942 AnimatedWidgetBaseState<AnimatedAlign> createState() => _AnimatedAlignState();
943
944 @override
945 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
946 super.debugFillProperties(properties);
947 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
948 }
949}
950
951class _AnimatedAlignState extends AnimatedWidgetBaseState<AnimatedAlign> {
952 AlignmentGeometryTween? _alignment;
953 Tween<double>? _heightFactorTween;
954 Tween<double>? _widthFactorTween;
955
956 @override
957 void forEachTween(TweenVisitor<dynamic> visitor) {
958 _alignment = visitor(_alignment, widget.alignment, (dynamic value) => AlignmentGeometryTween(begin: value as AlignmentGeometry)) as AlignmentGeometryTween?;
959 if (widget.heightFactor != null) {
960 _heightFactorTween = visitor(_heightFactorTween, widget.heightFactor, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
961 }
962 if (widget.widthFactor != null) {
963 _widthFactorTween = visitor(_widthFactorTween, widget.widthFactor, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
964 }
965 }
966
967 @override
968 Widget build(BuildContext context) {
969 return Align(
970 alignment: _alignment!.evaluate(animation)!,
971 heightFactor: _heightFactorTween?.evaluate(animation),
972 widthFactor: _widthFactorTween?.evaluate(animation),
973 child: widget.child,
974 );
975 }
976
977 @override
978 void debugFillProperties(DiagnosticPropertiesBuilder description) {
979 super.debugFillProperties(description);
980 description.add(DiagnosticsProperty<AlignmentGeometryTween>('alignment', _alignment, defaultValue: null));
981 description.add(DiagnosticsProperty<Tween<double>>('widthFactor', _widthFactorTween, defaultValue: null));
982 description.add(DiagnosticsProperty<Tween<double>>('heightFactor', _heightFactorTween, defaultValue: null));
983 }
984}
985
986/// Animated version of [Positioned] which automatically transitions the child's
987/// position over a given duration whenever the given position changes.
988///
989/// {@youtube 560 315 https://www.youtube.com/watch?v=hC3s2YdtWt8}
990///
991/// Only works if it's the child of a [Stack].
992///
993/// This widget is a good choice if the _size_ of the child would end up
994/// changing as a result of this animation. If the size is intended to remain
995/// the same, with only the _position_ changing over time, then consider
996/// [SlideTransition] instead. [SlideTransition] only triggers a repaint each
997/// frame of the animation, whereas [AnimatedPositioned] will trigger a relayout
998/// as well.
999///
1000/// Here's an illustration of what using this widget looks like, using a [curve]
1001/// of [Curves.fastOutSlowIn].
1002/// {@animation 250 266 https://flutter.github.io/assets-for-api-docs/assets/widgets/animated_positioned.mp4}
1003///
1004/// For the animation, you can choose a [curve] as well as a [duration] and the
1005/// widget will automatically animate to the new target position. If you require
1006/// more control over the animation (e.g. if you want to stop it mid-animation),
1007/// consider using a [PositionedTransition] instead, which takes a provided
1008/// [Animation] as an argument. While that allows you to fine-tune the animation,
1009/// it also requires more development overhead as you have to manually manage
1010/// the lifecycle of the underlying [AnimationController].
1011///
1012/// {@tool dartpad}
1013/// The following example transitions an AnimatedPositioned
1014/// between two states. It adjusts the `height`, `width`, and
1015/// [Positioned] properties when tapped.
1016///
1017/// ** See code in examples/api/lib/widgets/implicit_animations/animated_positioned.0.dart **
1018/// {@end-tool}
1019///
1020/// See also:
1021///
1022/// * [AnimatedPositionedDirectional], which adapts to the ambient
1023/// [Directionality] (the same as this widget, but for animating
1024/// [PositionedDirectional]).
1025class AnimatedPositioned extends ImplicitlyAnimatedWidget {
1026 /// Creates a widget that animates its position implicitly.
1027 ///
1028 /// Only two out of the three horizontal values ([left], [right],
1029 /// [width]), and only two out of the three vertical values ([top],
1030 /// [bottom], [height]), can be set. In each case, at least one of
1031 /// the three must be null.
1032 const AnimatedPositioned({
1033 super.key,
1034 required this.child,
1035 this.left,
1036 this.top,
1037 this.right,
1038 this.bottom,
1039 this.width,
1040 this.height,
1041 super.curve,
1042 required super.duration,
1043 super.onEnd,
1044 }) : assert(left == null || right == null || width == null),
1045 assert(top == null || bottom == null || height == null);
1046
1047 /// Creates a widget that animates the rectangle it occupies implicitly.
1048 AnimatedPositioned.fromRect({
1049 super.key,
1050 required this.child,
1051 required Rect rect,
1052 super.curve,
1053 required super.duration,
1054 super.onEnd,
1055 }) : left = rect.left,
1056 top = rect.top,
1057 width = rect.width,
1058 height = rect.height,
1059 right = null,
1060 bottom = null;
1061
1062 /// The widget below this widget in the tree.
1063 ///
1064 /// {@macro flutter.widgets.ProxyWidget.child}
1065 final Widget child;
1066
1067 /// The offset of the child's left edge from the left of the stack.
1068 final double? left;
1069
1070 /// The offset of the child's top edge from the top of the stack.
1071 final double? top;
1072
1073 /// The offset of the child's right edge from the right of the stack.
1074 final double? right;
1075
1076 /// The offset of the child's bottom edge from the bottom of the stack.
1077 final double? bottom;
1078
1079 /// The child's width.
1080 ///
1081 /// Only two out of the three horizontal values ([left], [right], [width]) can
1082 /// be set. The third must be null.
1083 final double? width;
1084
1085 /// The child's height.
1086 ///
1087 /// Only two out of the three vertical values ([top], [bottom], [height]) can
1088 /// be set. The third must be null.
1089 final double? height;
1090
1091 @override
1092 AnimatedWidgetBaseState<AnimatedPositioned> createState() => _AnimatedPositionedState();
1093
1094 @override
1095 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1096 super.debugFillProperties(properties);
1097 properties.add(DoubleProperty('left', left, defaultValue: null));
1098 properties.add(DoubleProperty('top', top, defaultValue: null));
1099 properties.add(DoubleProperty('right', right, defaultValue: null));
1100 properties.add(DoubleProperty('bottom', bottom, defaultValue: null));
1101 properties.add(DoubleProperty('width', width, defaultValue: null));
1102 properties.add(DoubleProperty('height', height, defaultValue: null));
1103 }
1104}
1105
1106class _AnimatedPositionedState extends AnimatedWidgetBaseState<AnimatedPositioned> {
1107 Tween<double>? _left;
1108 Tween<double>? _top;
1109 Tween<double>? _right;
1110 Tween<double>? _bottom;
1111 Tween<double>? _width;
1112 Tween<double>? _height;
1113
1114 @override
1115 void forEachTween(TweenVisitor<dynamic> visitor) {
1116 _left = visitor(_left, widget.left, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1117 _top = visitor(_top, widget.top, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1118 _right = visitor(_right, widget.right, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1119 _bottom = visitor(_bottom, widget.bottom, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1120 _width = visitor(_width, widget.width, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1121 _height = visitor(_height, widget.height, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1122 }
1123
1124 @override
1125 Widget build(BuildContext context) {
1126 return Positioned(
1127 left: _left?.evaluate(animation),
1128 top: _top?.evaluate(animation),
1129 right: _right?.evaluate(animation),
1130 bottom: _bottom?.evaluate(animation),
1131 width: _width?.evaluate(animation),
1132 height: _height?.evaluate(animation),
1133 child: widget.child,
1134 );
1135 }
1136
1137 @override
1138 void debugFillProperties(DiagnosticPropertiesBuilder description) {
1139 super.debugFillProperties(description);
1140 description.add(ObjectFlagProperty<Tween<double>>.has('left', _left));
1141 description.add(ObjectFlagProperty<Tween<double>>.has('top', _top));
1142 description.add(ObjectFlagProperty<Tween<double>>.has('right', _right));
1143 description.add(ObjectFlagProperty<Tween<double>>.has('bottom', _bottom));
1144 description.add(ObjectFlagProperty<Tween<double>>.has('width', _width));
1145 description.add(ObjectFlagProperty<Tween<double>>.has('height', _height));
1146 }
1147}
1148
1149/// Animated version of [PositionedDirectional] which automatically transitions
1150/// the child's position over a given duration whenever the given position
1151/// changes.
1152///
1153/// The ambient [Directionality] is used to determine whether [start] is to the
1154/// left or to the right.
1155///
1156/// Only works if it's the child of a [Stack].
1157///
1158/// This widget is a good choice if the _size_ of the child would end up
1159/// changing as a result of this animation. If the size is intended to remain
1160/// the same, with only the _position_ changing over time, then consider
1161/// [SlideTransition] instead. [SlideTransition] only triggers a repaint each
1162/// frame of the animation, whereas [AnimatedPositionedDirectional] will trigger
1163/// a relayout as well. ([SlideTransition] is also text-direction-aware.)
1164///
1165/// Here's an illustration of what using this widget looks like, using a [curve]
1166/// of [Curves.fastOutSlowIn].
1167/// {@animation 250 266 https://flutter.github.io/assets-for-api-docs/assets/widgets/animated_positioned_directional.mp4}
1168///
1169/// See also:
1170///
1171/// * [AnimatedPositioned], which specifies the widget's position visually (the
1172/// same as this widget, but for animating [Positioned]).
1173class AnimatedPositionedDirectional extends ImplicitlyAnimatedWidget {
1174 /// Creates a widget that animates its position implicitly.
1175 ///
1176 /// Only two out of the three horizontal values ([start], [end], [width]), and
1177 /// only two out of the three vertical values ([top], [bottom], [height]), can
1178 /// be set. In each case, at least one of the three must be null.
1179 const AnimatedPositionedDirectional({
1180 super.key,
1181 required this.child,
1182 this.start,
1183 this.top,
1184 this.end,
1185 this.bottom,
1186 this.width,
1187 this.height,
1188 super.curve,
1189 required super.duration,
1190 super.onEnd,
1191 }) : assert(start == null || end == null || width == null),
1192 assert(top == null || bottom == null || height == null);
1193
1194 /// The widget below this widget in the tree.
1195 ///
1196 /// {@macro flutter.widgets.ProxyWidget.child}
1197 final Widget child;
1198
1199 /// The offset of the child's start edge from the start of the stack.
1200 final double? start;
1201
1202 /// The offset of the child's top edge from the top of the stack.
1203 final double? top;
1204
1205 /// The offset of the child's end edge from the end of the stack.
1206 final double? end;
1207
1208 /// The offset of the child's bottom edge from the bottom of the stack.
1209 final double? bottom;
1210
1211 /// The child's width.
1212 ///
1213 /// Only two out of the three horizontal values ([start], [end], [width]) can
1214 /// be set. The third must be null.
1215 final double? width;
1216
1217 /// The child's height.
1218 ///
1219 /// Only two out of the three vertical values ([top], [bottom], [height]) can
1220 /// be set. The third must be null.
1221 final double? height;
1222
1223 @override
1224 AnimatedWidgetBaseState<AnimatedPositionedDirectional> createState() => _AnimatedPositionedDirectionalState();
1225
1226 @override
1227 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1228 super.debugFillProperties(properties);
1229 properties.add(DoubleProperty('start', start, defaultValue: null));
1230 properties.add(DoubleProperty('top', top, defaultValue: null));
1231 properties.add(DoubleProperty('end', end, defaultValue: null));
1232 properties.add(DoubleProperty('bottom', bottom, defaultValue: null));
1233 properties.add(DoubleProperty('width', width, defaultValue: null));
1234 properties.add(DoubleProperty('height', height, defaultValue: null));
1235 }
1236}
1237
1238class _AnimatedPositionedDirectionalState extends AnimatedWidgetBaseState<AnimatedPositionedDirectional> {
1239 Tween<double>? _start;
1240 Tween<double>? _top;
1241 Tween<double>? _end;
1242 Tween<double>? _bottom;
1243 Tween<double>? _width;
1244 Tween<double>? _height;
1245
1246 @override
1247 void forEachTween(TweenVisitor<dynamic> visitor) {
1248 _start = visitor(_start, widget.start, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1249 _top = visitor(_top, widget.top, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1250 _end = visitor(_end, widget.end, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1251 _bottom = visitor(_bottom, widget.bottom, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1252 _width = visitor(_width, widget.width, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1253 _height = visitor(_height, widget.height, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1254 }
1255
1256 @override
1257 Widget build(BuildContext context) {
1258 assert(debugCheckHasDirectionality(context));
1259 return Positioned.directional(
1260 textDirection: Directionality.of(context),
1261 start: _start?.evaluate(animation),
1262 top: _top?.evaluate(animation),
1263 end: _end?.evaluate(animation),
1264 bottom: _bottom?.evaluate(animation),
1265 width: _width?.evaluate(animation),
1266 height: _height?.evaluate(animation),
1267 child: widget.child,
1268 );
1269 }
1270
1271 @override
1272 void debugFillProperties(DiagnosticPropertiesBuilder description) {
1273 super.debugFillProperties(description);
1274 description.add(ObjectFlagProperty<Tween<double>>.has('start', _start));
1275 description.add(ObjectFlagProperty<Tween<double>>.has('top', _top));
1276 description.add(ObjectFlagProperty<Tween<double>>.has('end', _end));
1277 description.add(ObjectFlagProperty<Tween<double>>.has('bottom', _bottom));
1278 description.add(ObjectFlagProperty<Tween<double>>.has('width', _width));
1279 description.add(ObjectFlagProperty<Tween<double>>.has('height', _height));
1280 }
1281}
1282
1283/// Animated version of [Transform.scale] which automatically transitions the child's
1284/// scale over a given duration whenever the given scale changes.
1285///
1286/// {@tool snippet}
1287///
1288/// This code defines a widget that uses [AnimatedScale] to change the size
1289/// of [FlutterLogo] gradually to a new scale whenever the button is pressed.
1290///
1291/// ```dart
1292/// class LogoScale extends StatefulWidget {
1293/// const LogoScale({super.key});
1294///
1295/// @override
1296/// State<LogoScale> createState() => LogoScaleState();
1297/// }
1298///
1299/// class LogoScaleState extends State<LogoScale> {
1300/// double scale = 1.0;
1301///
1302/// void _changeScale() {
1303/// setState(() => scale = scale == 1.0 ? 3.0 : 1.0);
1304/// }
1305///
1306/// @override
1307/// Widget build(BuildContext context) {
1308/// return Column(
1309/// mainAxisAlignment: MainAxisAlignment.center,
1310/// children: <Widget>[
1311/// ElevatedButton(
1312/// onPressed: _changeScale,
1313/// child: const Text('Scale Logo'),
1314/// ),
1315/// Padding(
1316/// padding: const EdgeInsets.all(50),
1317/// child: AnimatedScale(
1318/// scale: scale,
1319/// duration: const Duration(seconds: 2),
1320/// child: const FlutterLogo(),
1321/// ),
1322/// ),
1323/// ],
1324/// );
1325/// }
1326/// }
1327/// ```
1328/// {@end-tool}
1329///
1330/// See also:
1331///
1332/// * [AnimatedRotation], for animating the rotation of a child.
1333/// * [AnimatedSize], for animating the resize of a child based on changes
1334/// in layout.
1335/// * [AnimatedSlide], for animating the translation of a child by a given offset relative to its size.
1336/// * [ScaleTransition], an explicitly animated version of this widget, where
1337/// an [Animation] is provided by the caller instead of being built in.
1338class AnimatedScale extends ImplicitlyAnimatedWidget {
1339 /// Creates a widget that animates its scale implicitly.
1340 const AnimatedScale({
1341 super.key,
1342 this.child,
1343 required this.scale,
1344 this.alignment = Alignment.center,
1345 this.filterQuality,
1346 super.curve,
1347 required super.duration,
1348 super.onEnd,
1349 });
1350
1351 /// The widget below this widget in the tree.
1352 ///
1353 /// {@macro flutter.widgets.ProxyWidget.child}
1354 final Widget? child;
1355
1356 /// The target scale.
1357 final double scale;
1358
1359 /// The alignment of the origin of the coordinate system in which the scale
1360 /// takes place, relative to the size of the box.
1361 ///
1362 /// For example, to set the origin of the scale to bottom middle, you can use
1363 /// an alignment of (0.0, 1.0).
1364 final Alignment alignment;
1365
1366 /// The filter quality with which to apply the transform as a bitmap operation.
1367 ///
1368 /// {@macro flutter.widgets.Transform.optional.FilterQuality}
1369 final FilterQuality? filterQuality;
1370
1371 @override
1372 ImplicitlyAnimatedWidgetState<AnimatedScale> createState() => _AnimatedScaleState();
1373
1374 @override
1375 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1376 super.debugFillProperties(properties);
1377 properties.add(DoubleProperty('scale', scale));
1378 properties.add(DiagnosticsProperty<Alignment>('alignment', alignment, defaultValue: Alignment.center));
1379 properties.add(EnumProperty<FilterQuality>('filterQuality', filterQuality, defaultValue: null));
1380 }
1381}
1382
1383class _AnimatedScaleState extends ImplicitlyAnimatedWidgetState<AnimatedScale> {
1384 Tween<double>? _scale;
1385 late Animation<double> _scaleAnimation;
1386
1387 @override
1388 void forEachTween(TweenVisitor<dynamic> visitor) {
1389 _scale = visitor(_scale, widget.scale, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1390 }
1391
1392 @override
1393 void didUpdateTweens() {
1394 _scaleAnimation = animation.drive(_scale!);
1395 }
1396
1397 @override
1398 Widget build(BuildContext context) {
1399 return ScaleTransition(
1400 scale: _scaleAnimation,
1401 alignment: widget.alignment,
1402 filterQuality: widget.filterQuality,
1403 child: widget.child,
1404 );
1405 }
1406}
1407
1408/// Animated version of [Transform.rotate] which automatically transitions the child's
1409/// rotation over a given duration whenever the given rotation changes.
1410///
1411/// {@tool snippet}
1412///
1413/// This code defines a widget that uses [AnimatedRotation] to rotate a [FlutterLogo]
1414/// gradually by an eighth of a turn (45 degrees) with each press of the button.
1415///
1416/// ```dart
1417/// class LogoRotate extends StatefulWidget {
1418/// const LogoRotate({super.key});
1419///
1420/// @override
1421/// State<LogoRotate> createState() => LogoRotateState();
1422/// }
1423///
1424/// class LogoRotateState extends State<LogoRotate> {
1425/// double turns = 0.0;
1426///
1427/// void _changeRotation() {
1428/// setState(() => turns += 1.0 / 8.0);
1429/// }
1430///
1431/// @override
1432/// Widget build(BuildContext context) {
1433/// return Column(
1434/// mainAxisAlignment: MainAxisAlignment.center,
1435/// children: <Widget>[
1436/// ElevatedButton(
1437/// onPressed: _changeRotation,
1438/// child: const Text('Rotate Logo'),
1439/// ),
1440/// Padding(
1441/// padding: const EdgeInsets.all(50),
1442/// child: AnimatedRotation(
1443/// turns: turns,
1444/// duration: const Duration(seconds: 1),
1445/// child: const FlutterLogo(),
1446/// ),
1447/// ),
1448/// ],
1449/// );
1450/// }
1451/// }
1452/// ```
1453/// {@end-tool}
1454///
1455/// See also:
1456///
1457/// * [AnimatedScale], for animating the scale of a child.
1458/// * [RotationTransition], an explicitly animated version of this widget, where
1459/// an [Animation] is provided by the caller instead of being built in.
1460class AnimatedRotation extends ImplicitlyAnimatedWidget {
1461 /// Creates a widget that animates its rotation implicitly.
1462 const AnimatedRotation({
1463 super.key,
1464 this.child,
1465 required this.turns,
1466 this.alignment = Alignment.center,
1467 this.filterQuality,
1468 super.curve,
1469 required super.duration,
1470 super.onEnd,
1471 });
1472
1473 /// The widget below this widget in the tree.
1474 ///
1475 /// {@macro flutter.widgets.ProxyWidget.child}
1476 final Widget? child;
1477
1478 /// The animation that controls the rotation of the child.
1479 ///
1480 /// If the current value of the turns animation is v, the child will be
1481 /// rotated v * 2 * pi radians before being painted.
1482 final double turns;
1483
1484 /// The alignment of the origin of the coordinate system in which the rotation
1485 /// takes place, relative to the size of the box.
1486 ///
1487 /// For example, to set the origin of the rotation to bottom middle, you can use
1488 /// an alignment of (0.0, 1.0).
1489 final Alignment alignment;
1490
1491 /// The filter quality with which to apply the transform as a bitmap operation.
1492 ///
1493 /// {@macro flutter.widgets.Transform.optional.FilterQuality}
1494 final FilterQuality? filterQuality;
1495
1496 @override
1497 ImplicitlyAnimatedWidgetState<AnimatedRotation> createState() => _AnimatedRotationState();
1498
1499 @override
1500 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1501 super.debugFillProperties(properties);
1502 properties.add(DoubleProperty('turns', turns));
1503 properties.add(DiagnosticsProperty<Alignment>('alignment', alignment, defaultValue: Alignment.center));
1504 properties.add(EnumProperty<FilterQuality>('filterQuality', filterQuality, defaultValue: null));
1505 }
1506}
1507
1508class _AnimatedRotationState extends ImplicitlyAnimatedWidgetState<AnimatedRotation> {
1509 Tween<double>? _turns;
1510 late Animation<double> _turnsAnimation;
1511
1512 @override
1513 void forEachTween(TweenVisitor<dynamic> visitor) {
1514 _turns = visitor(_turns, widget.turns, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1515 }
1516
1517 @override
1518 void didUpdateTweens() {
1519 _turnsAnimation = animation.drive(_turns!);
1520 }
1521
1522 @override
1523 Widget build(BuildContext context) {
1524 return RotationTransition(
1525 turns: _turnsAnimation,
1526 alignment: widget.alignment,
1527 filterQuality: widget.filterQuality,
1528 child: widget.child,
1529 );
1530 }
1531}
1532
1533/// Widget which automatically transitions the child's
1534/// offset relative to its normal position whenever the given offset changes.
1535///
1536/// The translation is expressed as an [Offset] scaled to the child's size. For
1537/// example, an [Offset] with a `dx` of 0.25 will result in a horizontal
1538/// translation of one quarter the width of the child.
1539///
1540/// {@tool dartpad}
1541/// This code defines a widget that uses [AnimatedSlide] to translate a [FlutterLogo]
1542/// up or down and right or left by dragging the X and Y axis sliders.
1543///
1544/// ** See code in examples/api/lib/widgets/implicit_animations/animated_slide.0.dart **
1545/// {@end-tool}
1546///
1547/// See also:
1548///
1549/// * [AnimatedPositioned], which, as a child of a [Stack], automatically
1550/// transitions its child's position over a given duration whenever the given
1551/// position changes.
1552/// * [AnimatedAlign], which automatically transitions its child's
1553/// position over a given duration whenever the given [AnimatedAlign.alignment] changes.
1554class AnimatedSlide extends ImplicitlyAnimatedWidget {
1555 /// Creates a widget that animates its offset translation implicitly.
1556 const AnimatedSlide({
1557 super.key,
1558 this.child,
1559 required this.offset,
1560 super.curve,
1561 required super.duration,
1562 super.onEnd,
1563 });
1564
1565 /// The widget below this widget in the tree.
1566 ///
1567 /// {@macro flutter.widgets.ProxyWidget.child}
1568 final Widget? child;
1569
1570 /// The target offset.
1571 /// The child will be translated horizontally by `width * dx` and vertically by `height * dy`
1572 final Offset offset;
1573
1574 @override
1575 ImplicitlyAnimatedWidgetState<AnimatedSlide> createState() => _AnimatedSlideState();
1576
1577 @override
1578 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1579 super.debugFillProperties(properties);
1580 properties.add(DiagnosticsProperty<Offset>('offset', offset));
1581 }
1582}
1583
1584class _AnimatedSlideState extends ImplicitlyAnimatedWidgetState<AnimatedSlide> {
1585 Tween<Offset>? _offset;
1586 late Animation<Offset> _offsetAnimation;
1587
1588 @override
1589 void forEachTween(TweenVisitor<dynamic> visitor) {
1590 _offset = visitor(_offset, widget.offset, (dynamic value) => Tween<Offset>(begin: value as Offset)) as Tween<Offset>?;
1591 }
1592
1593 @override
1594 void didUpdateTweens() {
1595 _offsetAnimation = animation.drive(_offset!);
1596 }
1597
1598 @override
1599 Widget build(BuildContext context) {
1600 return SlideTransition(
1601 position: _offsetAnimation,
1602 child: widget.child,
1603 );
1604 }
1605}
1606
1607/// Animated version of [Opacity] which automatically transitions the child's
1608/// opacity over a given duration whenever the given opacity changes.
1609///
1610/// {@youtube 560 315 https://www.youtube.com/watch?v=QZAvjqOqiLY}
1611///
1612/// Animating an opacity is relatively expensive because it requires painting
1613/// the child into an intermediate buffer.
1614///
1615/// Here's an illustration of what using this widget looks like, using a [curve]
1616/// of [Curves.fastOutSlowIn].
1617/// {@animation 250 266 https://flutter.github.io/assets-for-api-docs/assets/widgets/animated_opacity.mp4}
1618///
1619/// {@tool snippet}
1620///
1621/// ```dart
1622/// class LogoFade extends StatefulWidget {
1623/// const LogoFade({super.key});
1624///
1625/// @override
1626/// State<LogoFade> createState() => LogoFadeState();
1627/// }
1628///
1629/// class LogoFadeState extends State<LogoFade> {
1630/// double opacityLevel = 1.0;
1631///
1632/// void _changeOpacity() {
1633/// setState(() => opacityLevel = opacityLevel == 0 ? 1.0 : 0.0);
1634/// }
1635///
1636/// @override
1637/// Widget build(BuildContext context) {
1638/// return Column(
1639/// mainAxisAlignment: MainAxisAlignment.center,
1640/// children: <Widget>[
1641/// AnimatedOpacity(
1642/// opacity: opacityLevel,
1643/// duration: const Duration(seconds: 3),
1644/// child: const FlutterLogo(),
1645/// ),
1646/// ElevatedButton(
1647/// onPressed: _changeOpacity,
1648/// child: const Text('Fade Logo'),
1649/// ),
1650/// ],
1651/// );
1652/// }
1653/// }
1654/// ```
1655/// {@end-tool}
1656///
1657/// ## Hit testing
1658///
1659/// Setting the [opacity] to zero does not prevent hit testing from being
1660/// applied to the descendants of the [AnimatedOpacity] widget. This can be
1661/// confusing for the user, who may not see anything, and may believe the area
1662/// of the interface where the [AnimatedOpacity] is hiding a widget to be
1663/// non-interactive.
1664///
1665/// With certain widgets, such as [Flow], that compute their positions only when
1666/// they are painted, this can actually lead to bugs (from unexpected geometry
1667/// to exceptions), because those widgets are not painted by the [AnimatedOpacity]
1668/// widget at all when the [opacity] animation reaches zero.
1669///
1670/// To avoid such problems, it is generally a good idea to use an
1671/// [IgnorePointer] widget when setting the [opacity] to zero. This prevents
1672/// interactions with any children in the subtree when the [child] is animating
1673/// away.
1674///
1675/// See also:
1676///
1677/// * [AnimatedCrossFade], for fading between two children.
1678/// * [AnimatedSwitcher], for fading between many children in sequence.
1679/// * [FadeTransition], an explicitly animated version of this widget, where
1680/// an [Animation] is provided by the caller instead of being built in.
1681/// * [SliverAnimatedOpacity], for automatically transitioning a _sliver's_
1682/// opacity over a given duration whenever the given opacity changes.
1683class AnimatedOpacity extends ImplicitlyAnimatedWidget {
1684 /// Creates a widget that animates its opacity implicitly.
1685 ///
1686 /// The [opacity] argument must be between zero and one, inclusive.
1687 const AnimatedOpacity({
1688 super.key,
1689 this.child,
1690 required this.opacity,
1691 super.curve,
1692 required super.duration,
1693 super.onEnd,
1694 this.alwaysIncludeSemantics = false,
1695 }) : assert(opacity >= 0.0 && opacity <= 1.0);
1696
1697 /// The widget below this widget in the tree.
1698 ///
1699 /// {@macro flutter.widgets.ProxyWidget.child}
1700 final Widget? child;
1701
1702 /// The target opacity.
1703 ///
1704 /// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent
1705 /// (i.e., invisible).
1706 final double opacity;
1707
1708 /// Whether the semantic information of the children is always included.
1709 ///
1710 /// Defaults to false.
1711 ///
1712 /// When true, regardless of the opacity settings the child semantic
1713 /// information is exposed as if the widget were fully visible. This is
1714 /// useful in cases where labels may be hidden during animations that
1715 /// would otherwise contribute relevant semantics.
1716 final bool alwaysIncludeSemantics;
1717
1718 @override
1719 ImplicitlyAnimatedWidgetState<AnimatedOpacity> createState() => _AnimatedOpacityState();
1720
1721 @override
1722 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1723 super.debugFillProperties(properties);
1724 properties.add(DoubleProperty('opacity', opacity));
1725 }
1726}
1727
1728class _AnimatedOpacityState extends ImplicitlyAnimatedWidgetState<AnimatedOpacity> {
1729 Tween<double>? _opacity;
1730 late Animation<double> _opacityAnimation;
1731
1732 @override
1733 void forEachTween(TweenVisitor<dynamic> visitor) {
1734 _opacity = visitor(_opacity, widget.opacity, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1735 }
1736
1737 @override
1738 void didUpdateTweens() {
1739 _opacityAnimation = animation.drive(_opacity!);
1740 }
1741
1742 @override
1743 Widget build(BuildContext context) {
1744 return FadeTransition(
1745 opacity: _opacityAnimation,
1746 alwaysIncludeSemantics: widget.alwaysIncludeSemantics,
1747 child: widget.child,
1748 );
1749 }
1750}
1751
1752/// Animated version of [SliverOpacity] which automatically transitions the
1753/// sliver child's opacity over a given duration whenever the given opacity
1754/// changes.
1755///
1756/// Animating an opacity is relatively expensive because it requires painting
1757/// the sliver child into an intermediate buffer.
1758///
1759/// Here's an illustration of what using this widget looks like, using a [curve]
1760/// of [Curves.fastOutSlowIn].
1761///
1762/// {@tool dartpad}
1763/// Creates a [CustomScrollView] with a [SliverFixedExtentList] and a
1764/// [FloatingActionButton]. Pressing the button animates the lists' opacity.
1765///
1766/// ** See code in examples/api/lib/widgets/implicit_animations/sliver_animated_opacity.0.dart **
1767/// {@end-tool}
1768///
1769/// ## Hit testing
1770///
1771/// Setting the [opacity] to zero does not prevent hit testing from being
1772/// applied to the descendants of the [SliverAnimatedOpacity] widget. This can
1773/// be confusing for the user, who may not see anything, and may believe the
1774/// area of the interface where the [SliverAnimatedOpacity] is hiding a widget
1775/// to be non-interactive.
1776///
1777/// With certain widgets, such as [Flow], that compute their positions only when
1778/// they are painted, this can actually lead to bugs (from unexpected geometry
1779/// to exceptions), because those widgets are not painted by the
1780/// [SliverAnimatedOpacity] widget at all when the [opacity] animation reaches
1781/// zero.
1782///
1783/// To avoid such problems, it is generally a good idea to use a
1784/// [SliverIgnorePointer] widget when setting the [opacity] to zero. This
1785/// prevents interactions with any children in the subtree when the [sliver] is
1786/// animating away.
1787///
1788/// See also:
1789///
1790/// * [SliverFadeTransition], an explicitly animated version of this widget, where
1791/// an [Animation] is provided by the caller instead of being built in.
1792/// * [AnimatedOpacity], for automatically transitioning a box child's
1793/// opacity over a given duration whenever the given opacity changes.
1794class SliverAnimatedOpacity extends ImplicitlyAnimatedWidget {
1795 /// Creates a widget that animates its opacity implicitly.
1796 ///
1797 /// The [opacity] argument must be between zero and one, inclusive.
1798 const SliverAnimatedOpacity({
1799 super.key,
1800 this.sliver,
1801 required this.opacity,
1802 super.curve,
1803 required super.duration,
1804 super.onEnd,
1805 this.alwaysIncludeSemantics = false,
1806 }) : assert(opacity >= 0.0 && opacity <= 1.0);
1807
1808 /// The sliver below this widget in the tree.
1809 final Widget? sliver;
1810
1811 /// The target opacity.
1812 ///
1813 /// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent
1814 /// (i.e., invisible).
1815 final double opacity;
1816
1817 /// Whether the semantic information of the children is always included.
1818 ///
1819 /// Defaults to false.
1820 ///
1821 /// When true, regardless of the opacity settings the sliver child's semantic
1822 /// information is exposed as if the widget were fully visible. This is
1823 /// useful in cases where labels may be hidden during animations that
1824 /// would otherwise contribute relevant semantics.
1825 final bool alwaysIncludeSemantics;
1826
1827 @override
1828 ImplicitlyAnimatedWidgetState<SliverAnimatedOpacity> createState() => _SliverAnimatedOpacityState();
1829
1830 @override
1831 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1832 super.debugFillProperties(properties);
1833 properties.add(DoubleProperty('opacity', opacity));
1834 }
1835}
1836
1837class _SliverAnimatedOpacityState extends ImplicitlyAnimatedWidgetState<SliverAnimatedOpacity> {
1838 Tween<double>? _opacity;
1839 late Animation<double> _opacityAnimation;
1840
1841 @override
1842 void forEachTween(TweenVisitor<dynamic> visitor) {
1843 _opacity = visitor(_opacity, widget.opacity, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
1844 }
1845
1846 @override
1847 void didUpdateTweens() {
1848 _opacityAnimation = animation.drive(_opacity!);
1849 }
1850
1851 @override
1852 Widget build(BuildContext context) {
1853 return SliverFadeTransition(
1854 opacity: _opacityAnimation,
1855 sliver: widget.sliver,
1856 alwaysIncludeSemantics: widget.alwaysIncludeSemantics,
1857 );
1858 }
1859}
1860
1861/// Animated version of [DefaultTextStyle] which automatically transitions the
1862/// default text style (the text style to apply to descendant [Text] widgets
1863/// without explicit style) over a given duration whenever the given style
1864/// changes.
1865///
1866/// The [textAlign], [softWrap], [overflow], [maxLines], [textWidthBasis]
1867/// and [textHeightBehavior] properties are not animated and take effect
1868/// immediately when changed.
1869///
1870/// Here's an illustration of what using this widget looks like, using a [curve]
1871/// of [Curves.elasticInOut].
1872/// {@animation 250 266 https://flutter.github.io/assets-for-api-docs/assets/widgets/animated_default_text_style.mp4}
1873///
1874/// For the animation, you can choose a [curve] as well as a [duration] and the
1875/// widget will automatically animate to the new default text style. If you require
1876/// more control over the animation (e.g. if you want to stop it mid-animation),
1877/// consider using a [DefaultTextStyleTransition] instead, which takes a provided
1878/// [Animation] as argument. While that allows you to fine-tune the animation,
1879/// it also requires more development overhead as you have to manually manage
1880/// the lifecycle of the underlying [AnimationController].
1881class AnimatedDefaultTextStyle extends ImplicitlyAnimatedWidget {
1882 /// Creates a widget that animates the default text style implicitly.
1883 const AnimatedDefaultTextStyle({
1884 super.key,
1885 required this.child,
1886 required this.style,
1887 this.textAlign,
1888 this.softWrap = true,
1889 this.overflow = TextOverflow.clip,
1890 this.maxLines,
1891 this.textWidthBasis = TextWidthBasis.parent,
1892 this.textHeightBehavior,
1893 super.curve,
1894 required super.duration,
1895 super.onEnd,
1896 }) : assert(maxLines == null || maxLines > 0);
1897
1898 /// The widget below this widget in the tree.
1899 ///
1900 /// {@macro flutter.widgets.ProxyWidget.child}
1901 final Widget child;
1902
1903 /// The target text style.
1904 ///
1905 /// When this property is changed, the style will be animated over [duration] time.
1906 final TextStyle style;
1907
1908 /// How the text should be aligned horizontally.
1909 ///
1910 /// This property takes effect immediately when changed, it is not animated.
1911 final TextAlign? textAlign;
1912
1913 /// Whether the text should break at soft line breaks.
1914 ///
1915 /// This property takes effect immediately when changed, it is not animated.
1916 ///
1917 /// See [DefaultTextStyle.softWrap] for more details.
1918 final bool softWrap;
1919
1920 /// How visual overflow should be handled.
1921 ///
1922 /// This property takes effect immediately when changed, it is not animated.
1923 final TextOverflow overflow;
1924
1925 /// An optional maximum number of lines for the text to span, wrapping if necessary.
1926 ///
1927 /// This property takes effect immediately when changed, it is not animated.
1928 ///
1929 /// See [DefaultTextStyle.maxLines] for more details.
1930 final int? maxLines;
1931
1932 /// The strategy to use when calculating the width of the Text.
1933 ///
1934 /// See [TextWidthBasis] for possible values and their implications.
1935 final TextWidthBasis textWidthBasis;
1936
1937 /// {@macro dart.ui.textHeightBehavior}
1938 final ui.TextHeightBehavior? textHeightBehavior;
1939
1940 @override
1941 AnimatedWidgetBaseState<AnimatedDefaultTextStyle> createState() => _AnimatedDefaultTextStyleState();
1942
1943 @override
1944 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
1945 super.debugFillProperties(properties);
1946 style.debugFillProperties(properties);
1947 properties.add(EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: null));
1948 properties.add(FlagProperty('softWrap', value: softWrap, ifTrue: 'wrapping at box width', ifFalse: 'no wrapping except at line break characters', showName: true));
1949 properties.add(EnumProperty<TextOverflow>('overflow', overflow, defaultValue: null));
1950 properties.add(IntProperty('maxLines', maxLines, defaultValue: null));
1951 properties.add(EnumProperty<TextWidthBasis>('textWidthBasis', textWidthBasis, defaultValue: TextWidthBasis.parent));
1952 properties.add(DiagnosticsProperty<ui.TextHeightBehavior>('textHeightBehavior', textHeightBehavior, defaultValue: null));
1953 }
1954}
1955
1956class _AnimatedDefaultTextStyleState extends AnimatedWidgetBaseState<AnimatedDefaultTextStyle> {
1957 TextStyleTween? _style;
1958
1959 @override
1960 void forEachTween(TweenVisitor<dynamic> visitor) {
1961 _style = visitor(_style, widget.style, (dynamic value) => TextStyleTween(begin: value as TextStyle)) as TextStyleTween?;
1962 }
1963
1964 @override
1965 Widget build(BuildContext context) {
1966 return DefaultTextStyle(
1967 style: _style!.evaluate(animation),
1968 textAlign: widget.textAlign,
1969 softWrap: widget.softWrap,
1970 overflow: widget.overflow,
1971 maxLines: widget.maxLines,
1972 textWidthBasis: widget.textWidthBasis,
1973 textHeightBehavior: widget.textHeightBehavior,
1974 child: widget.child,
1975 );
1976 }
1977}
1978
1979/// Animated version of [PhysicalModel].
1980///
1981/// The [borderRadius] and [elevation] are animated.
1982///
1983/// The [color] is animated if the [animateColor] property is set; otherwise,
1984/// the color changes immediately at the start of the animation for the other
1985/// two properties. This allows the color to be animated independently (e.g.
1986/// because it is being driven by an [AnimatedTheme]).
1987///
1988/// The [shape] is not animated.
1989///
1990/// Here's an illustration of what using this widget looks like, using a [curve]
1991/// of [Curves.fastOutSlowIn].
1992/// {@animation 250 266 https://flutter.github.io/assets-for-api-docs/assets/widgets/animated_physical_model.mp4}
1993class AnimatedPhysicalModel extends ImplicitlyAnimatedWidget {
1994 /// Creates a widget that animates the properties of a [PhysicalModel].
1995 ///
1996 /// The [elevation] must be non-negative.
1997 ///
1998 /// Animating [color] is optional and is controlled by the [animateColor] flag.
1999 ///
2000 /// Animating [shadowColor] is optional and is controlled by the [animateShadowColor] flag.
2001 const AnimatedPhysicalModel({
2002 super.key,
2003 required this.child,
2004 this.shape = BoxShape.rectangle,
2005 this.clipBehavior = Clip.none,
2006 this.borderRadius,
2007 this.elevation = 0.0,
2008 required this.color,
2009 this.animateColor = true,
2010 required this.shadowColor,
2011 this.animateShadowColor = true,
2012 super.curve,
2013 required super.duration,
2014 super.onEnd,
2015 }) : assert(elevation >= 0.0);
2016
2017 /// The widget below this widget in the tree.
2018 ///
2019 /// {@macro flutter.widgets.ProxyWidget.child}
2020 final Widget child;
2021
2022 /// The type of shape.
2023 ///
2024 /// This property is not animated.
2025 final BoxShape shape;
2026
2027 /// {@macro flutter.material.Material.clipBehavior}
2028 ///
2029 /// Defaults to [Clip.none].
2030 final Clip clipBehavior;
2031
2032 /// The target border radius of the rounded corners for a rectangle shape.
2033 ///
2034 /// If null, treated as [BorderRadius.zero].
2035 final BorderRadius? borderRadius;
2036
2037 /// The target z-coordinate relative to the parent at which to place this
2038 /// physical object.
2039 ///
2040 /// The value will always be non-negative.
2041 final double elevation;
2042
2043 /// The target background color.
2044 final Color color;
2045
2046 /// Whether the color should be animated.
2047 final bool animateColor;
2048
2049 /// The target shadow color.
2050 final Color shadowColor;
2051
2052 /// Whether the shadow color should be animated.
2053 final bool animateShadowColor;
2054
2055 @override
2056 AnimatedWidgetBaseState<AnimatedPhysicalModel> createState() => _AnimatedPhysicalModelState();
2057
2058 @override
2059 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
2060 super.debugFillProperties(properties);
2061 properties.add(EnumProperty<BoxShape>('shape', shape));
2062 properties.add(DiagnosticsProperty<BorderRadius>('borderRadius', borderRadius));
2063 properties.add(DoubleProperty('elevation', elevation));
2064 properties.add(ColorProperty('color', color));
2065 properties.add(DiagnosticsProperty<bool>('animateColor', animateColor));
2066 properties.add(ColorProperty('shadowColor', shadowColor));
2067 properties.add(DiagnosticsProperty<bool>('animateShadowColor', animateShadowColor));
2068 }
2069}
2070
2071class _AnimatedPhysicalModelState extends AnimatedWidgetBaseState<AnimatedPhysicalModel> {
2072 BorderRadiusTween? _borderRadius;
2073 Tween<double>? _elevation;
2074 ColorTween? _color;
2075 ColorTween? _shadowColor;
2076
2077 @override
2078 void forEachTween(TweenVisitor<dynamic> visitor) {
2079 _borderRadius = visitor(
2080 _borderRadius,
2081 widget.borderRadius ?? BorderRadius.zero,
2082 (dynamic value) => BorderRadiusTween(begin: value as BorderRadius),
2083 ) as BorderRadiusTween?;
2084 _elevation = visitor(
2085 _elevation,
2086 widget.elevation,
2087 (dynamic value) => Tween<double>(begin: value as double),
2088 ) as Tween<double>?;
2089 _color = visitor(
2090 _color,
2091 widget.color,
2092 (dynamic value) => ColorTween(begin: value as Color),
2093 ) as ColorTween?;
2094 _shadowColor = visitor(
2095 _shadowColor,
2096 widget.shadowColor,
2097 (dynamic value) => ColorTween(begin: value as Color),
2098 ) as ColorTween?;
2099 }
2100
2101 @override
2102 Widget build(BuildContext context) {
2103 return PhysicalModel(
2104 shape: widget.shape,
2105 clipBehavior: widget.clipBehavior,
2106 borderRadius: _borderRadius!.evaluate(animation),
2107 elevation: _elevation!.evaluate(animation),
2108 color: widget.animateColor ? _color!.evaluate(animation)! : widget.color,
2109 shadowColor: widget.animateShadowColor
2110 ? _shadowColor!.evaluate(animation)!
2111 : widget.shadowColor,
2112 child: widget.child,
2113 );
2114 }
2115}
2116
2117/// Animated version of [FractionallySizedBox] which automatically transitions the
2118/// child's size over a given duration whenever the given [widthFactor] or
2119/// [heightFactor] changes, as well as the position whenever the given [alignment]
2120/// changes.
2121///
2122/// For the animation, you can choose a [curve] as well as a [duration] and the
2123/// widget will automatically animate to the new target [widthFactor] or
2124/// [heightFactor].
2125///
2126/// {@tool dartpad}
2127/// The following example transitions an [AnimatedFractionallySizedBox]
2128/// between two states. It adjusts the [heightFactor], [widthFactor], and
2129/// [alignment] properties when tapped, using a [curve] of [Curves.fastOutSlowIn]
2130///
2131/// ** See code in examples/api/lib/widgets/implicit_animations/animated_fractionally_sized_box.0.dart **
2132/// {@end-tool}
2133///
2134/// See also:
2135///
2136/// * [AnimatedAlign], which is an implicitly animated version of [Align].
2137/// * [AnimatedContainer], which can transition more values at once.
2138/// * [AnimatedSlide], which can animate the translation of child by a given offset relative to its size.
2139/// * [AnimatedPositioned], which, as a child of a [Stack], automatically
2140/// transitions its child's position over a given duration whenever the given
2141/// position changes.
2142class AnimatedFractionallySizedBox extends ImplicitlyAnimatedWidget {
2143 /// Creates a widget that sizes its child to a fraction of the total available
2144 /// space that animates implicitly, and positions its child by an alignment
2145 /// that animates implicitly.
2146 ///
2147 /// If non-null, the [widthFactor] and [heightFactor] arguments must be
2148 /// non-negative.
2149 const AnimatedFractionallySizedBox({
2150 super.key,
2151 this.alignment = Alignment.center,
2152 this.child,
2153 this.heightFactor,
2154 this.widthFactor,
2155 super.curve,
2156 required super.duration,
2157 super.onEnd,
2158 }) : assert(widthFactor == null || widthFactor >= 0.0),
2159 assert(heightFactor == null || heightFactor >= 0.0);
2160
2161 /// The widget below this widget in the tree.
2162 ///
2163 /// {@macro flutter.widgets.ProxyWidget.child}
2164 final Widget? child;
2165
2166 /// {@macro flutter.widgets.basic.fractionallySizedBox.heightFactor}
2167 final double? heightFactor;
2168
2169 /// {@macro flutter.widgets.basic.fractionallySizedBox.widthFactor}
2170 final double? widthFactor;
2171
2172 /// {@macro flutter.widgets.basic.fractionallySizedBox.alignment}
2173 final AlignmentGeometry alignment;
2174
2175 @override
2176 AnimatedWidgetBaseState<AnimatedFractionallySizedBox> createState() => _AnimatedFractionallySizedBoxState();
2177
2178 @override
2179 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
2180 super.debugFillProperties(properties);
2181 properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
2182 properties.add(DiagnosticsProperty<double>('widthFactor', widthFactor));
2183 properties.add(DiagnosticsProperty<double>('heightFactor', heightFactor));
2184 }
2185}
2186
2187class _AnimatedFractionallySizedBoxState extends AnimatedWidgetBaseState<AnimatedFractionallySizedBox> {
2188 AlignmentGeometryTween? _alignment;
2189 Tween<double>? _heightFactorTween;
2190 Tween<double>? _widthFactorTween;
2191
2192 @override
2193 void forEachTween(TweenVisitor<dynamic> visitor) {
2194 _alignment = visitor(_alignment, widget.alignment, (dynamic value) => AlignmentGeometryTween(begin: value as AlignmentGeometry)) as AlignmentGeometryTween?;
2195 if (widget.heightFactor != null) {
2196 _heightFactorTween = visitor(_heightFactorTween, widget.heightFactor, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
2197 }
2198 if (widget.widthFactor != null) {
2199 _widthFactorTween = visitor(_widthFactorTween, widget.widthFactor, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>?;
2200 }
2201 }
2202
2203 @override
2204 Widget build(BuildContext context) {
2205 return FractionallySizedBox(
2206 alignment: _alignment!.evaluate(animation)!,
2207 heightFactor: _heightFactorTween?.evaluate(animation),
2208 widthFactor: _widthFactorTween?.evaluate(animation),
2209 child: widget.child,
2210 );
2211 }
2212
2213 @override
2214 void debugFillProperties(DiagnosticPropertiesBuilder description) {
2215 super.debugFillProperties(description);
2216 description.add(DiagnosticsProperty<AlignmentGeometryTween>('alignment', _alignment, defaultValue: null));
2217 description.add(DiagnosticsProperty<Tween<double>>('widthFactor', _widthFactorTween, defaultValue: null));
2218 description.add(DiagnosticsProperty<Tween<double>>('heightFactor', _heightFactorTween, defaultValue: null));
2219 }
2220}
2221