@@ -225,51 +225,51 @@ class SlideTransition extends AnimatedWidget {
225225 }
226226}
227227
228- /// Animates the scale of a transformed widget .
228+ /// Signature for the callback to [MatrixTransition.onTransform] .
229229///
230- /// Here's an illustration of the [ScaleTransition] widget, with it's [alignment]
231- /// animated by a [CurvedAnimation] set to [Curves.fastOutSlowIn] :
232- /// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/scale_transition.mp4}
233- ///
234- /// {@tool dartpad}
235- /// The following code implements the [ScaleTransition] as seen in the video
236- /// above:
230+ /// Computes a [Matrix4] to be used in the [MatrixTransition] transformed widget
231+ /// from the [MatrixTransition.animation] value.
232+ typedef TransformCallback = Matrix4 Function (double animationValue);
233+
234+ /// Animates the [Matrix4] of a transformed widget.
237235///
238- /// ** See code in examples/api/lib/widgets/transitions/scale_transition.0.dart **
239- /// {@end-tool}
236+ /// The [onTransform] callback computes a [Matrix4] from the animated value, it
237+ /// is called every time the [animation] changes its value.
240238///
241239/// See also:
242240///
243- /// * [PositionedTransition] , a widget that animates its child from a start
244- /// position to an end position over the lifetime of the animation.
245- /// * [RelativePositionedTransition] , a widget that transitions its child's
246- /// position based on the value of a rectangle relative to a bounding box.
247- /// * [SizeTransition] , a widget that animates its own size and clips and
248- /// aligns its child.
249- class ScaleTransition extends AnimatedWidget {
250- /// Creates a scale transition.
241+ /// * [ScaleTransition] , which animates the scale of a widget, by providing a
242+ /// matrix which scales along the X and Y axis.
243+ /// * [RotationTransition] , which animates the rotation of a widget, by
244+ /// providing a matrix which rotates along the Z axis.
245+ class MatrixTransition extends AnimatedWidget {
246+ /// Creates a matrix transition.
251247 ///
252- /// The [scale] argument must not be null. The [alignment] argument defaults
253- /// to [Alignment.center] .
254- const ScaleTransition ({
248+ /// The [alignment] argument defaults to [Alignment.center] .
249+ const MatrixTransition ({
255250 super .key,
256- required Animation <double > scale,
251+ required Animation <double > animation,
252+ required this .onTransform,
257253 this .alignment = Alignment .center,
258254 this .filterQuality,
259255 this .child,
260- }) : super (listenable: scale );
256+ }) : super (listenable: animation );
261257
262- /// The animation that controls the scale of the child.
258+ /// The callback to compute a [Matrix4] from the [animation] . It's called
259+ /// every time [animation] changes its value.
260+ final TransformCallback onTransform;
261+
262+ /// The animation that controls the matrix of the child.
263263 ///
264- /// If the current value of the scale animation is v, the child will be
265- /// painted v times its normal size .
266- Animation <double > get scale => listenable as Animation <double >;
264+ /// The matrix will be computed from the animation with the [onTransform]
265+ /// callback .
266+ Animation <double > get animation => listenable as Animation <double >;
267267
268- /// The alignment of the origin of the coordinate system in which the scale
269- /// takes place, relative to the size of the box.
268+ /// The alignment of the origin of the coordinate system in which the
269+ /// transform takes place, relative to the size of the box.
270270 ///
271- /// For example, to set the origin of the scale to bottom middle, you can use
272- /// an alignment of (0.0, 1.0).
271+ /// For example, to set the origin of the transform to bottom middle, you can
272+ /// use an alignment of (0.0, 1.0).
273273 final Alignment alignment;
274274
275275 /// The filter quality with which to apply the transform as a bitmap operation.
@@ -292,23 +292,66 @@ class ScaleTransition extends AnimatedWidget {
292292 // but leaving it in the layer tree before the animation has started or after
293293 // it has finished significantly hurts performance.
294294 final bool useFilterQuality;
295- switch (scale .status) {
295+ switch (animation .status) {
296296 case AnimationStatus .dismissed:
297297 case AnimationStatus .completed:
298298 useFilterQuality = false ;
299299 case AnimationStatus .forward:
300300 case AnimationStatus .reverse:
301301 useFilterQuality = true ;
302302 }
303- return Transform . scale (
304- scale : scale .value,
303+ return Transform (
304+ transform : onTransform (animation .value) ,
305305 alignment: alignment,
306306 filterQuality: useFilterQuality ? filterQuality : null ,
307307 child: child,
308308 );
309309 }
310310}
311311
312+ /// Animates the scale of a transformed widget.
313+ ///
314+ /// Here's an illustration of the [ScaleTransition] widget, with it's [alignment]
315+ /// animated by a [CurvedAnimation] set to [Curves.fastOutSlowIn] :
316+ /// {@animation 300 378 https://flutter.github.io/assets-for-api-docs/assets/widgets/scale_transition.mp4}
317+ ///
318+ /// {@tool dartpad}
319+ /// The following code implements the [ScaleTransition] as seen in the video
320+ /// above:
321+ ///
322+ /// ** See code in examples/api/lib/widgets/transitions/scale_transition.0.dart **
323+ /// {@end-tool}
324+ ///
325+ /// See also:
326+ ///
327+ /// * [PositionedTransition] , a widget that animates its child from a start
328+ /// position to an end position over the lifetime of the animation.
329+ /// * [RelativePositionedTransition] , a widget that transitions its child's
330+ /// position based on the value of a rectangle relative to a bounding box.
331+ /// * [SizeTransition] , a widget that animates its own size and clips and
332+ /// aligns its child.
333+ class ScaleTransition extends MatrixTransition {
334+ /// Creates a scale transition.
335+ ///
336+ /// The [alignment] argument defaults to [Alignment.center] .
337+ const ScaleTransition ({
338+ super .key,
339+ required Animation <double > scale,
340+ super .alignment = Alignment .center,
341+ super .filterQuality,
342+ super .child,
343+ }) : super (animation: scale, onTransform: _handleScaleMatrix);
344+
345+ /// The animation that controls the scale of the child.
346+ Animation <double > get scale => animation;
347+
348+ /// The callback that controls the scale of the child.
349+ ///
350+ /// If the current value of the animation is v, the child will be
351+ /// painted v times its normal size.
352+ static Matrix4 _handleScaleMatrix (double value) => Matrix4 .diagonal3Values (value, value, 1.0 );
353+ }
354+
312355/// Animates the rotation of a widget.
313356///
314357/// Here's an illustration of the [RotationTransition] widget, with it's [turns]
@@ -328,66 +371,26 @@ class ScaleTransition extends AnimatedWidget {
328371/// widget.
329372/// * [SizeTransition] , a widget that animates its own size and clips and
330373/// aligns its child.
331- class RotationTransition extends AnimatedWidget {
374+ class RotationTransition extends MatrixTransition {
332375 /// Creates a rotation transition.
333376 ///
334377 /// The [turns] argument must not be null.
335378 const RotationTransition ({
336379 super .key,
337380 required Animation <double > turns,
338- this .alignment = Alignment .center,
339- this .filterQuality,
340- this .child,
341- }) : super (listenable : turns);
381+ super .alignment = Alignment .center,
382+ super .filterQuality,
383+ super .child,
384+ }) : super (animation : turns, onTransform : _handleTurnsMatrix );
342385
343386 /// The animation that controls the rotation of the child.
344- ///
345- /// If the current value of the turns animation is v, the child will be
346- /// rotated v * 2 * pi radians before being painted.
347- Animation <double > get turns => listenable as Animation <double >;
348-
349- /// The alignment of the origin of the coordinate system around which the
350- /// rotation occurs, relative to the size of the box.
351- ///
352- /// For example, to set the origin of the rotation to top right corner, use
353- /// an alignment of (1.0, -1.0) or use [Alignment.topRight]
354- final Alignment alignment;
355-
356- /// The filter quality with which to apply the transform as a bitmap operation.
357- ///
358- /// When the animation is stopped (either in [AnimationStatus.dismissed] or
359- /// [AnimationStatus.completed] ), the filter quality argument will be ignored.
360- ///
361- /// {@macro flutter.widgets.Transform.optional.FilterQuality}
362- final FilterQuality ? filterQuality;
387+ Animation <double > get turns => animation;
363388
364- /// The widget below this widget in the tree .
389+ /// The callback that controls the rotation of the child .
365390 ///
366- /// {@macro flutter.widgets.ProxyWidget.child}
367- final Widget ? child;
368-
369- @override
370- Widget build (BuildContext context) {
371- // The ImageFilter layer created by setting filterQuality will introduce
372- // a saveLayer call. This is usually worthwhile when animating the layer,
373- // but leaving it in the layer tree before the animation has started or after
374- // it has finished significantly hurts performance.
375- final bool useFilterQuality;
376- switch (turns.status) {
377- case AnimationStatus .dismissed:
378- case AnimationStatus .completed:
379- useFilterQuality = false ;
380- case AnimationStatus .forward:
381- case AnimationStatus .reverse:
382- useFilterQuality = true ;
383- }
384- return Transform .rotate (
385- angle: turns.value * math.pi * 2.0 ,
386- alignment: alignment,
387- filterQuality: useFilterQuality ? filterQuality : null ,
388- child: child,
389- );
390- }
391+ /// If the current value of the animation is v, the child will be rotated
392+ /// v * 2 * pi radians before being painted.
393+ static Matrix4 _handleTurnsMatrix (double value) => Matrix4 .rotationZ (value * math.pi * 2.0 );
391394}
392395
393396/// Animates its own size and clips and aligns its child.
0 commit comments