diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index 43c9fa2195..b9077e8e6f 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -1262,10 +1262,13 @@ class Transform extends SingleChildRenderObjectWidget { alignment = null, super(key: key, child: child); - /// Creates a widget that scales its child uniformly. + /// Creates a widget that scales its child along the 2D plane. /// - /// The `scale` argument must not be null. It gives the scalar by which - /// to multiply the `x` and `y` axes. + /// The `scaleX` argument provides the scalar by which to multiply the `x` axis, and the `scaleY` argument provides the scalar by which to multiply the `y` axis. Either may be omitted, in which case that axis defaults to 1.0. + /// + /// For convenience, to scale the child uniformly, instead of providing `scaleX` and `scaleY`, the `scale` parameter may be used. + /// + /// At least one of `scale`, `scaleX`, and `scaleY` must be non-null. If `scale` is provided, the other two must be null; similarly, if it is not provided, one of the other two must be provided. /// /// The [alignment] controls the origin of the scale; by default, this is /// the center of the box. @@ -1293,14 +1296,18 @@ class Transform extends SingleChildRenderObjectWidget { /// over a given duration. Transform.scale({ Key? key, - required double scale, + double? scale, + double? scaleX, + double? scaleY, this.origin, this.alignment = Alignment.center, this.transformHitTests = true, this.filterQuality, Widget? child, - }) : transform = Matrix4.diagonal3Values(scale, scale, 1.0), - super(key: key, child: child); + }) : assert(!(scale == null && scaleX == null && scaleY == null), "At least one of 'scale', 'scaleX' and 'scaleY' is required to be non-null"), + assert(scale == null || (scaleX == null && scaleY == null), "If 'scale' is non-null then 'scaleX' and 'scaleY' must be left null"), + transform = Matrix4.diagonal3Values(scale ?? scaleX ?? 1.0, scale ?? scaleY ?? 1.0, 1.0), + super(key: key, child: child); /// The matrix to transform the child by during painting. final Matrix4 transform; diff --git a/packages/flutter/test/widgets/transform_test.dart b/packages/flutter/test/widgets/transform_test.dart index aa0027fc09..f1e38aad35 100644 --- a/packages/flutter/test/widgets/transform_test.dart +++ b/packages/flutter/test/widgets/transform_test.dart @@ -505,6 +505,93 @@ void main() { matchesGoldenFile('transform_golden.BitmapRotate.png'), ); }); + + testWidgets("Transform.scale() does not accept all three 'scale', 'scaleX' and 'scaleY' parameters to be non-null", (WidgetTester tester) async { + await expectLater(() { + tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: Transform.scale( + scale: 1.0, + scaleX: 1.0, + scaleY: 1.0, + child: const SizedBox( + height: 100, + width: 100, + ), + ), + ))); + }, throwsAssertionError); + }); + + testWidgets("Transform.scale() needs at least one of 'scale', 'scaleX' and 'scaleY' to be non-null, otherwise throws AssertionError", (WidgetTester tester) async { + await expectLater(() { + tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: Transform.scale( + child: const SizedBox( + height: 100, + width: 100, + ), + ), + ))); + }, throwsAssertionError); + }); + + testWidgets("Transform.scale() scales widget uniformly with 'scale' parameter", (WidgetTester tester) async { + const double _scale = 1.5; + const double _height = 100; + const double _width = 150; + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: SizedBox( + height: 400, + width: 400, + child: Center( + child: Transform.scale( + scale: _scale, + child: Container( + height: _height, + width: _width, + decoration: const BoxDecoration(), + ), + ), + ), + ))); + + const Size _target = Size(_width * _scale, _height * _scale); + + expect(tester.getBottomRight(find.byType(Container)), _target.bottomRight(tester.getTopLeft(find.byType(Container)))); + }); + + testWidgets("Transform.scale() scales widget according to 'scaleX' and 'scaleY'", (WidgetTester tester) async { + const double _scaleX = 1.5; + const double _scaleY = 1.2; + const double _height = 100; + const double _width = 150; + await tester.pumpWidget(Directionality( + textDirection: TextDirection.ltr, + child: SizedBox( + height: 400, + width: 400, + child: Center( + child: Transform.scale( + scaleX: _scaleX, + scaleY: _scaleY, + child: Container( + height: _height, + width: _width, + decoration: const BoxDecoration(), + ), + ), + ), + ))); + + const Size _target = Size(_width * _scaleX, _height * _scaleY); + + expect(tester.getBottomRight(find.byType(Container)), _target.bottomRight(tester.getTopLeft(find.byType(Container)))); + }); } class TestRectPainter extends CustomPainter {