Skip to content

prefer_transform_over_container

v0.4.0 Warning Fix Widget Replacement

Flags Container widgets that only use the transform parameter (plus optional key and child). When Container is used solely for a transform, the Transform widget is a lighter, more descriptive alternative.

With only transform set, the Container collapses to a single Transform. Writing Transform directly also puts the named constructors in reach — Transform.rotate, Transform.scale, Transform.translate — which are far easier to read than a hand-built Matrix4. The quick fix does the rename; the matrix moves across as-is.

See also: Transform | Matrix4

// A "SALE" ribbon tilted across a product tile.
Container(
transform: Matrix4.rotationZ(-math.pi / 12),
child: const Text('SALE'),
);
Transform(
transform: Matrix4.rotationZ(-math.pi / 12),
child: const Text('SALE'),
);

Once it is a Transform, most cases have a constructor that spells out the intent — and unlike the raw matrix, they take an alignment:

// Don't
Container(
transform: Matrix4.rotationZ(-math.pi / 12),
child: const Text('SALE'),
);
// Do — rotates about the centre rather than the top-left corner
Transform.rotate(
angle: -math.pi / 12,
child: const Text('SALE'),
);

The quick fix will not do this step for you; it only renames the widget.

// Don't
Container(
key: const ValueKey('ribbon'),
transform: Matrix4.rotationZ(math.pi / 4),
child: const Text('Rotated'),
);
// Do
Transform(
key: const ValueKey('ribbon'),
transform: Matrix4.rotationZ(math.pi / 4),
child: const Text('Rotated'),
);

Any other argument silences it, including transformAlignment — which is the argument you would reach for next:

// Not reported: transformAlignment has no equivalent on a plain Transform,
// which takes `origin` and `alignment` instead.
Container(
transform: Matrix4.rotationZ(math.pi / 4),
transformAlignment: Alignment.center,
child: const Text('Rotated'),
);

The equivalent is Transform(transform: …, alignment: Alignment.center, …), but that is a rename plus an argument rename, so the rule leaves it alone.

A transform does not affect layout. Both widgets paint the transformed child while laying it out untransformed, so the rewrite changes nothing about the render — it is purely a simplification.

This rule is in the opinionated preset, so it is on with preset: opinionated, or by name:

many_lints.yaml
rules:
prefer_transform_over_container: true

To turn it off again:

many_lints.yaml
rules:
prefer_transform_over_container: false

To keep the rule on but skip certain paths, use per-rule exclude.