Unverified Commit 2bb19a95 authored by Fedor Blagodyr's avatar Fedor Blagodyr Committed by GitHub

Added onEnd callback into AnimatedSize (#139859)

close #106439
parent 5a5683dd
......@@ -82,6 +82,7 @@ class RenderAnimatedSize extends RenderAligningShiftedBox {
super.textDirection,
super.child,
Clip clipBehavior = Clip.hardEdge,
VoidCallback? onEnd,
}) : _vsync = vsync,
_clipBehavior = clipBehavior {
_controller = AnimationController(
......@@ -97,6 +98,7 @@ class RenderAnimatedSize extends RenderAligningShiftedBox {
parent: _controller,
curve: curve,
);
_onEnd = onEnd;
}
/// When asserts are enabled, returns the animation controller that is used
......@@ -203,6 +205,19 @@ class RenderAnimatedSize extends RenderAligningShiftedBox {
_controller.resync(vsync);
}
/// Called every time an animation completes.
///
/// This can be useful to trigger additional actions (e.g. another animation)
/// at the end of the current animation.
VoidCallback? get onEnd => _onEnd;
VoidCallback? _onEnd;
set onEnd(VoidCallback? value) {
if (value == _onEnd) {
return;
}
_onEnd = value;
}
@override
void attach(PipelineOwner owner) {
super.attach(owner);
......@@ -216,11 +231,13 @@ class RenderAnimatedSize extends RenderAligningShiftedBox {
// already, to resume interrupted resizing animation.
markNeedsLayout();
}
_controller.addStatusListener(_animationStatusListener);
}
@override
void detach() {
_controller.stop();
_controller.removeStatusListener(_animationStatusListener);
super.detach();
}
......@@ -363,6 +380,16 @@ class RenderAnimatedSize extends RenderAligningShiftedBox {
}
}
void _animationStatusListener(AnimationStatus status) {
switch (status) {
case AnimationStatus.completed:
_onEnd?.call();
case AnimationStatus.dismissed:
case AnimationStatus.forward:
case AnimationStatus.reverse:
}
}
@override
void paint(PaintingContext context, Offset offset) {
if (child != null && _hasVisualOverflow && clipBehavior != Clip.none) {
......
......@@ -31,6 +31,7 @@ class AnimatedSize extends StatefulWidget {
required this.duration,
this.reverseDuration,
this.clipBehavior = Clip.hardEdge,
this.onEnd,
});
/// The widget below this widget in the tree.
......@@ -78,6 +79,12 @@ class AnimatedSize extends StatefulWidget {
/// Defaults to [Clip.hardEdge].
final Clip clipBehavior;
/// Called every time an animation completes.
///
/// This can be useful to trigger additional actions (e.g. another animation)
/// at the end of the current animation.
final VoidCallback? onEnd;
@override
State<AnimatedSize> createState() => _AnimatedSizeState();
}
......@@ -93,6 +100,7 @@ class _AnimatedSizeState
reverseDuration: widget.reverseDuration,
vsync: this,
clipBehavior: widget.clipBehavior,
onEnd: widget.onEnd,
child: widget.child,
);
}
......@@ -107,6 +115,7 @@ class _AnimatedSize extends SingleChildRenderObjectWidget {
this.reverseDuration,
required this.vsync,
this.clipBehavior = Clip.hardEdge,
this.onEnd,
});
final AlignmentGeometry alignment;
......@@ -119,6 +128,8 @@ class _AnimatedSize extends SingleChildRenderObjectWidget {
final Clip clipBehavior;
final VoidCallback? onEnd;
@override
RenderAnimatedSize createRenderObject(BuildContext context) {
return RenderAnimatedSize(
......@@ -129,6 +140,7 @@ class _AnimatedSize extends SingleChildRenderObjectWidget {
vsync: vsync,
textDirection: Directionality.maybeOf(context),
clipBehavior: clipBehavior,
onEnd: onEnd,
);
}
......@@ -141,7 +153,8 @@ class _AnimatedSize extends SingleChildRenderObjectWidget {
..curve = curve
..vsync = vsync
..textDirection = Directionality.maybeOf(context)
..clipBehavior = clipBehavior;
..clipBehavior = clipBehavior
..onEnd = onEnd;
}
@override
......
......@@ -87,6 +87,61 @@ void main() {
expect(box.size.height, equals(100.0));
});
testWidgets('calls onEnd when animation is completed', (WidgetTester tester) async {
int callCount = 0;
void handleEnd() {
callCount++;
}
await tester.pumpWidget(
Center(
child: AnimatedSize(
onEnd: handleEnd,
duration: const Duration(milliseconds: 200),
child: const SizedBox(
width: 100.0,
height: 100.0,
),
),
),
);
expect(callCount, equals(0));
await tester.pumpWidget(
Center(
child: AnimatedSize(
onEnd: handleEnd,
duration: const Duration(milliseconds: 200),
child: const SizedBox(
width: 200.0,
height: 200.0,
),
),
),
);
expect(callCount, equals(0));
await tester.pumpAndSettle();
expect(callCount, equals(1));
await tester.pumpWidget(
Center(
child: AnimatedSize(
onEnd: handleEnd,
duration: const Duration(milliseconds: 200),
child: const SizedBox(
width: 100.0,
height: 100.0,
),
),
),
);
await tester.pumpAndSettle();
expect(callCount, equals(2));
});
testWidgets('clamps animated size to constraints', (WidgetTester tester) async {
await tester.pumpWidget(
const Center(
......
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