Unverified Commit b77753b9 authored by Andre's avatar Andre Committed by GitHub

Add transformAlignment and clipBehavior to AnimatedContainer (#67046)

* Add transformAlignment and clipBehavior to AnimatedContainer, make Container.transformAlignment an AlignmentGeometry.

* Add clipBehavior test

* Fix comment

* Clarify clipBehavior animation
parent f8b1de3a
...@@ -352,14 +352,14 @@ class Container extends StatelessWidget { ...@@ -352,14 +352,14 @@ class Container extends StatelessWidget {
/// The transformation matrix to apply before painting the container. /// The transformation matrix to apply before painting the container.
final Matrix4? transform; final Matrix4? transform;
/// The alignment of the origin, relative to the size of the container, if [transform] is specified. /// The alignment of the origin, relative to the size of the container, if [transform] is specified.
/// ///
/// When [transform] is null, the value of this property is ignored. /// When [transform] is null, the value of this property is ignored.
/// ///
/// See also: /// See also:
/// ///
/// * [Transform.alignment], which is set by this property. /// * [Transform.alignment], which is set by this property.
final Alignment? transformAlignment; final AlignmentGeometry? transformAlignment;
/// The clip behavior when [Container.decoration] is not null. /// The clip behavior when [Container.decoration] is not null.
/// ///
......
...@@ -635,7 +635,9 @@ class AnimatedContainer extends ImplicitlyAnimatedWidget { ...@@ -635,7 +635,9 @@ class AnimatedContainer extends ImplicitlyAnimatedWidget {
BoxConstraints? constraints, BoxConstraints? constraints,
this.margin, this.margin,
this.transform, this.transform,
this.transformAlignment,
this.child, this.child,
this.clipBehavior = Clip.none,
Curve curve = Curves.linear, Curve curve = Curves.linear,
required Duration duration, required Duration duration,
VoidCallback? onEnd, VoidCallback? onEnd,
...@@ -709,6 +711,28 @@ class AnimatedContainer extends ImplicitlyAnimatedWidget { ...@@ -709,6 +711,28 @@ class AnimatedContainer extends ImplicitlyAnimatedWidget {
/// The transformation matrix to apply before painting the container. /// The transformation matrix to apply before painting the container.
final Matrix4? transform; final Matrix4? transform;
/// The alignment of the origin, relative to the size of the container, if [transform] is specified.
///
/// When [transform] is null, the value of this property is ignored.
///
/// See also:
///
/// * [Transform.alignment], which is set by this property.
final AlignmentGeometry? transformAlignment;
/// The clip behavior when [AnimatedContainer.decoration] is not null.
///
/// Defaults to [Clip.none]. Must be [Clip.none] if [decoration] is null.
///
/// Unlike other properties of [AnimatedContainer], changes to this property
/// apply immediately and have no animation.
///
/// If a clip is to be applied, the [Decoration.getClipPath] method
/// for the provided decoration must return a clip path. (This is not
/// supported by all decorations; the default implementation of that
/// method throws an [UnsupportedError].)
final Clip clipBehavior;
@override @override
_AnimatedContainerState createState() => _AnimatedContainerState(); _AnimatedContainerState createState() => _AnimatedContainerState();
...@@ -722,6 +746,8 @@ class AnimatedContainer extends ImplicitlyAnimatedWidget { ...@@ -722,6 +746,8 @@ class AnimatedContainer extends ImplicitlyAnimatedWidget {
properties.add(DiagnosticsProperty<BoxConstraints>('constraints', constraints, defaultValue: null, showName: false)); properties.add(DiagnosticsProperty<BoxConstraints>('constraints', constraints, defaultValue: null, showName: false));
properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('margin', margin, defaultValue: null)); properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('margin', margin, defaultValue: null));
properties.add(ObjectFlagProperty<Matrix4>.has('transform', transform)); properties.add(ObjectFlagProperty<Matrix4>.has('transform', transform));
properties.add(DiagnosticsProperty<AlignmentGeometry>('transformAlignment', transformAlignment, defaultValue: null));
properties.add(DiagnosticsProperty<Clip>('clipBehavior', clipBehavior));
} }
} }
...@@ -733,6 +759,7 @@ class _AnimatedContainerState extends AnimatedWidgetBaseState<AnimatedContainer> ...@@ -733,6 +759,7 @@ class _AnimatedContainerState extends AnimatedWidgetBaseState<AnimatedContainer>
BoxConstraintsTween? _constraints; BoxConstraintsTween? _constraints;
EdgeInsetsGeometryTween? _margin; EdgeInsetsGeometryTween? _margin;
Matrix4Tween? _transform; Matrix4Tween? _transform;
AlignmentGeometryTween? _transformAlignment;
@override @override
void forEachTween(TweenVisitor<dynamic> visitor) { void forEachTween(TweenVisitor<dynamic> visitor) {
...@@ -743,19 +770,23 @@ class _AnimatedContainerState extends AnimatedWidgetBaseState<AnimatedContainer> ...@@ -743,19 +770,23 @@ class _AnimatedContainerState extends AnimatedWidgetBaseState<AnimatedContainer>
_constraints = visitor(_constraints, widget.constraints, (dynamic value) => BoxConstraintsTween(begin: value as BoxConstraints)) as BoxConstraintsTween?; _constraints = visitor(_constraints, widget.constraints, (dynamic value) => BoxConstraintsTween(begin: value as BoxConstraints)) as BoxConstraintsTween?;
_margin = visitor(_margin, widget.margin, (dynamic value) => EdgeInsetsGeometryTween(begin: value as EdgeInsetsGeometry)) as EdgeInsetsGeometryTween?; _margin = visitor(_margin, widget.margin, (dynamic value) => EdgeInsetsGeometryTween(begin: value as EdgeInsetsGeometry)) as EdgeInsetsGeometryTween?;
_transform = visitor(_transform, widget.transform, (dynamic value) => Matrix4Tween(begin: value as Matrix4)) as Matrix4Tween?; _transform = visitor(_transform, widget.transform, (dynamic value) => Matrix4Tween(begin: value as Matrix4)) as Matrix4Tween?;
_transformAlignment = visitor(_transformAlignment, widget.transformAlignment, (dynamic value) => AlignmentGeometryTween(begin: value as AlignmentGeometry)) as AlignmentGeometryTween?;
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final Animation<double> animation = this.animation!;
return Container( return Container(
child: widget.child, child: widget.child,
alignment: _alignment?.evaluate(animation!), alignment: _alignment?.evaluate(animation),
padding: _padding?.evaluate(animation!), padding: _padding?.evaluate(animation),
decoration: _decoration?.evaluate(animation!), decoration: _decoration?.evaluate(animation),
foregroundDecoration: _foregroundDecoration?.evaluate(animation!), foregroundDecoration: _foregroundDecoration?.evaluate(animation),
constraints: _constraints?.evaluate(animation!), constraints: _constraints?.evaluate(animation),
margin: _margin?.evaluate(animation!), margin: _margin?.evaluate(animation),
transform: _transform?.evaluate(animation!), transform: _transform?.evaluate(animation),
transformAlignment: _transformAlignment?.evaluate(animation),
clipBehavior: widget.clipBehavior,
); );
} }
...@@ -769,6 +800,7 @@ class _AnimatedContainerState extends AnimatedWidgetBaseState<AnimatedContainer> ...@@ -769,6 +800,7 @@ class _AnimatedContainerState extends AnimatedWidgetBaseState<AnimatedContainer>
description.add(DiagnosticsProperty<BoxConstraintsTween>('constraints', _constraints, showName: false, defaultValue: null)); description.add(DiagnosticsProperty<BoxConstraintsTween>('constraints', _constraints, showName: false, defaultValue: null));
description.add(DiagnosticsProperty<EdgeInsetsGeometryTween>('margin', _margin, defaultValue: null)); description.add(DiagnosticsProperty<EdgeInsetsGeometryTween>('margin', _margin, defaultValue: null));
description.add(ObjectFlagProperty<Matrix4Tween>.has('transform', _transform)); description.add(ObjectFlagProperty<Matrix4Tween>.has('transform', _transform));
description.add(DiagnosticsProperty<AlignmentGeometryTween>('transformAlignment', _transformAlignment, defaultValue: null));
} }
} }
......
...@@ -286,4 +286,74 @@ void main() { ...@@ -286,4 +286,74 @@ void main() {
expect(text.size.width, equals(200.0)); expect(text.size.width, equals(200.0));
expect(text.size.height, equals(100.0)); expect(text.size.height, equals(100.0));
}); });
testWidgets('AnimatedContainer sets transformAlignment', (WidgetTester tester) async {
final Key target = UniqueKey();
await tester.pumpWidget(
Center(
child: Directionality(
textDirection: TextDirection.ltr,
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
child: SizedBox(key: target, width: 100.0, height: 200.0),
transform: Matrix4.diagonal3Values(0.5, 0.5, 1),
transformAlignment: Alignment.topLeft,
),
),
),
);
expect(tester.getSize(find.byKey(target)), const Size(100.0, 200.0));
expect(tester.getTopLeft(find.byKey(target)), const Offset(350.0, 200.0));
await tester.pumpWidget(
Center(
child: Directionality(
textDirection: TextDirection.ltr,
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
child: SizedBox(key: target, width: 100.0, height: 200.0),
transform: Matrix4.diagonal3Values(0.5, 0.5, 1),
transformAlignment: Alignment.bottomRight,
),
),
),
);
expect(tester.getSize(find.byKey(target)), const Size(100.0, 200.0));
expect(tester.getTopLeft(find.byKey(target)), const Offset(350.0, 200.0));
await tester.pump(const Duration(milliseconds: 100));
expect(tester.getSize(find.byKey(target)), const Size(100.0, 200.0));
expect(tester.getTopLeft(find.byKey(target)), const Offset(375.0, 250.0));
await tester.pump(const Duration(milliseconds: 500));
expect(tester.getSize(find.byKey(target)), const Size(100.0, 200.0));
expect(tester.getTopLeft(find.byKey(target)), const Offset(400.0, 300.0));
});
testWidgets('AnimatedContainer sets clipBehavior', (WidgetTester tester) async {
await tester.pumpWidget(
AnimatedContainer(
decoration: const BoxDecoration(
color: Color(0xFFED1D7F),
),
duration: const Duration(milliseconds: 200),
)
);
expect(tester.firstWidget<Container>(find.byType(Container)).clipBehavior, Clip.none);
await tester.pumpWidget(
AnimatedContainer(
decoration: const BoxDecoration(
color: Color(0xFFED1D7F),
),
duration: const Duration(milliseconds: 200),
clipBehavior: Clip.antiAlias,
)
);
expect(tester.firstWidget<Container>(find.byType(Container)).clipBehavior, Clip.antiAlias);
});
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment