Adding onEnd callback to implicit animated widgets (#38979)
This commit is contained in:
parent
4373a31971
commit
d4a016443b
@ -227,10 +227,11 @@ class AnimatedTheme extends ImplicitlyAnimatedWidget {
|
|||||||
this.isMaterialAppTheme = false,
|
this.isMaterialAppTheme = false,
|
||||||
Curve curve = Curves.linear,
|
Curve curve = Curves.linear,
|
||||||
Duration duration = kThemeAnimationDuration,
|
Duration duration = kThemeAnimationDuration,
|
||||||
|
VoidCallback onEnd,
|
||||||
@required this.child,
|
@required this.child,
|
||||||
}) : assert(child != null),
|
}) : assert(child != null),
|
||||||
assert(data != null),
|
assert(data != null),
|
||||||
super(key: key, curve: curve, duration: duration);
|
super(key: key, curve: curve, duration: duration, onEnd: onEnd);
|
||||||
|
|
||||||
/// Specifies the color and typography values for descendant widgets.
|
/// Specifies the color and typography values for descendant widgets.
|
||||||
final ThemeData data;
|
final ThemeData data;
|
||||||
|
@ -276,6 +276,7 @@ abstract class ImplicitlyAnimatedWidget extends StatefulWidget {
|
|||||||
Key key,
|
Key key,
|
||||||
this.curve = Curves.linear,
|
this.curve = Curves.linear,
|
||||||
@required this.duration,
|
@required this.duration,
|
||||||
|
this.onEnd,
|
||||||
}) : assert(curve != null),
|
}) : assert(curve != null),
|
||||||
assert(duration != null),
|
assert(duration != null),
|
||||||
super(key: key);
|
super(key: key);
|
||||||
@ -286,6 +287,12 @@ abstract class ImplicitlyAnimatedWidget extends StatefulWidget {
|
|||||||
/// The duration over which to animate the parameters of this container.
|
/// The duration over which to animate the parameters of this container.
|
||||||
final Duration duration;
|
final Duration duration;
|
||||||
|
|
||||||
|
/// 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
|
@override
|
||||||
ImplicitlyAnimatedWidgetState<ImplicitlyAnimatedWidget> createState();
|
ImplicitlyAnimatedWidgetState<ImplicitlyAnimatedWidget> createState();
|
||||||
|
|
||||||
@ -356,6 +363,17 @@ abstract class ImplicitlyAnimatedWidgetState<T extends ImplicitlyAnimatedWidget>
|
|||||||
debugLabel: kDebugMode ? '${widget.toStringShort()}' : null,
|
debugLabel: kDebugMode ? '${widget.toStringShort()}' : null,
|
||||||
vsync: this,
|
vsync: this,
|
||||||
);
|
);
|
||||||
|
_controller.addStatusListener((AnimationStatus status) {
|
||||||
|
switch (status) {
|
||||||
|
case AnimationStatus.completed:
|
||||||
|
if (widget.onEnd != null)
|
||||||
|
widget.onEnd();
|
||||||
|
break;
|
||||||
|
case AnimationStatus.dismissed:
|
||||||
|
case AnimationStatus.forward:
|
||||||
|
case AnimationStatus.reverse:
|
||||||
|
}
|
||||||
|
});
|
||||||
_updateCurve();
|
_updateCurve();
|
||||||
_constructTweens();
|
_constructTweens();
|
||||||
didUpdateTweens();
|
didUpdateTweens();
|
||||||
@ -624,6 +642,7 @@ class AnimatedContainer extends ImplicitlyAnimatedWidget {
|
|||||||
this.child,
|
this.child,
|
||||||
Curve curve = Curves.linear,
|
Curve curve = Curves.linear,
|
||||||
@required Duration duration,
|
@required Duration duration,
|
||||||
|
VoidCallback onEnd,
|
||||||
}) : assert(margin == null || margin.isNonNegative),
|
}) : assert(margin == null || margin.isNonNegative),
|
||||||
assert(padding == null || padding.isNonNegative),
|
assert(padding == null || padding.isNonNegative),
|
||||||
assert(decoration == null || decoration.debugAssertIsValid()),
|
assert(decoration == null || decoration.debugAssertIsValid()),
|
||||||
@ -638,7 +657,7 @@ class AnimatedContainer extends ImplicitlyAnimatedWidget {
|
|||||||
? constraints?.tighten(width: width, height: height)
|
? constraints?.tighten(width: width, height: height)
|
||||||
?? BoxConstraints.tightFor(width: width, height: height)
|
?? BoxConstraints.tightFor(width: width, height: height)
|
||||||
: constraints,
|
: constraints,
|
||||||
super(key: key, curve: curve, duration: duration);
|
super(key: key, curve: curve, duration: duration, onEnd: onEnd);
|
||||||
|
|
||||||
/// The [child] contained by the container.
|
/// The [child] contained by the container.
|
||||||
///
|
///
|
||||||
@ -780,9 +799,10 @@ class AnimatedPadding extends ImplicitlyAnimatedWidget {
|
|||||||
this.child,
|
this.child,
|
||||||
Curve curve = Curves.linear,
|
Curve curve = Curves.linear,
|
||||||
@required Duration duration,
|
@required Duration duration,
|
||||||
|
VoidCallback onEnd,
|
||||||
}) : assert(padding != null),
|
}) : assert(padding != null),
|
||||||
assert(padding.isNonNegative),
|
assert(padding.isNonNegative),
|
||||||
super(key: key, curve: curve, duration: duration);
|
super(key: key, curve: curve, duration: duration, onEnd: onEnd);
|
||||||
|
|
||||||
/// The amount of space by which to inset the child.
|
/// The amount of space by which to inset the child.
|
||||||
final EdgeInsetsGeometry padding;
|
final EdgeInsetsGeometry padding;
|
||||||
@ -859,8 +879,9 @@ class AnimatedAlign extends ImplicitlyAnimatedWidget {
|
|||||||
this.child,
|
this.child,
|
||||||
Curve curve = Curves.linear,
|
Curve curve = Curves.linear,
|
||||||
@required Duration duration,
|
@required Duration duration,
|
||||||
|
VoidCallback onEnd,
|
||||||
}) : assert(alignment != null),
|
}) : assert(alignment != null),
|
||||||
super(key: key, curve: curve, duration: duration);
|
super(key: key, curve: curve, duration: duration, onEnd: onEnd);
|
||||||
|
|
||||||
/// How to align the child.
|
/// How to align the child.
|
||||||
///
|
///
|
||||||
@ -967,9 +988,10 @@ class AnimatedPositioned extends ImplicitlyAnimatedWidget {
|
|||||||
this.height,
|
this.height,
|
||||||
Curve curve = Curves.linear,
|
Curve curve = Curves.linear,
|
||||||
@required Duration duration,
|
@required Duration duration,
|
||||||
|
VoidCallback onEnd,
|
||||||
}) : assert(left == null || right == null || width == null),
|
}) : assert(left == null || right == null || width == null),
|
||||||
assert(top == null || bottom == null || height == null),
|
assert(top == null || bottom == null || height == null),
|
||||||
super(key: key, curve: curve, duration: duration);
|
super(key: key, curve: curve, duration: duration, onEnd: onEnd);
|
||||||
|
|
||||||
/// Creates a widget that animates the rectangle it occupies implicitly.
|
/// Creates a widget that animates the rectangle it occupies implicitly.
|
||||||
///
|
///
|
||||||
@ -980,13 +1002,14 @@ class AnimatedPositioned extends ImplicitlyAnimatedWidget {
|
|||||||
Rect rect,
|
Rect rect,
|
||||||
Curve curve = Curves.linear,
|
Curve curve = Curves.linear,
|
||||||
@required Duration duration,
|
@required Duration duration,
|
||||||
|
VoidCallback onEnd,
|
||||||
}) : left = rect.left,
|
}) : left = rect.left,
|
||||||
top = rect.top,
|
top = rect.top,
|
||||||
width = rect.width,
|
width = rect.width,
|
||||||
height = rect.height,
|
height = rect.height,
|
||||||
right = null,
|
right = null,
|
||||||
bottom = null,
|
bottom = null,
|
||||||
super(key: key, curve: curve, duration: duration);
|
super(key: key, curve: curve, duration: duration, onEnd: onEnd);
|
||||||
|
|
||||||
/// The widget below this widget in the tree.
|
/// The widget below this widget in the tree.
|
||||||
///
|
///
|
||||||
@ -1118,9 +1141,10 @@ class AnimatedPositionedDirectional extends ImplicitlyAnimatedWidget {
|
|||||||
this.height,
|
this.height,
|
||||||
Curve curve = Curves.linear,
|
Curve curve = Curves.linear,
|
||||||
@required Duration duration,
|
@required Duration duration,
|
||||||
|
VoidCallback onEnd,
|
||||||
}) : assert(start == null || end == null || width == null),
|
}) : assert(start == null || end == null || width == null),
|
||||||
assert(top == null || bottom == null || height == null),
|
assert(top == null || bottom == null || height == null),
|
||||||
super(key: key, curve: curve, duration: duration);
|
super(key: key, curve: curve, duration: duration, onEnd: onEnd);
|
||||||
|
|
||||||
/// The widget below this widget in the tree.
|
/// The widget below this widget in the tree.
|
||||||
///
|
///
|
||||||
@ -1274,9 +1298,10 @@ class AnimatedOpacity extends ImplicitlyAnimatedWidget {
|
|||||||
@required this.opacity,
|
@required this.opacity,
|
||||||
Curve curve = Curves.linear,
|
Curve curve = Curves.linear,
|
||||||
@required Duration duration,
|
@required Duration duration,
|
||||||
|
VoidCallback onEnd,
|
||||||
this.alwaysIncludeSemantics = false,
|
this.alwaysIncludeSemantics = false,
|
||||||
}) : assert(opacity != null && opacity >= 0.0 && opacity <= 1.0),
|
}) : assert(opacity != null && opacity >= 0.0 && opacity <= 1.0),
|
||||||
super(key: key, curve: curve, duration: duration);
|
super(key: key, curve: curve, duration: duration, onEnd: onEnd);
|
||||||
|
|
||||||
/// The widget below this widget in the tree.
|
/// The widget below this widget in the tree.
|
||||||
///
|
///
|
||||||
@ -1369,12 +1394,13 @@ class AnimatedDefaultTextStyle extends ImplicitlyAnimatedWidget {
|
|||||||
this.maxLines,
|
this.maxLines,
|
||||||
Curve curve = Curves.linear,
|
Curve curve = Curves.linear,
|
||||||
@required Duration duration,
|
@required Duration duration,
|
||||||
|
VoidCallback onEnd,
|
||||||
}) : assert(style != null),
|
}) : assert(style != null),
|
||||||
assert(child != null),
|
assert(child != null),
|
||||||
assert(softWrap != null),
|
assert(softWrap != null),
|
||||||
assert(overflow != null),
|
assert(overflow != null),
|
||||||
assert(maxLines == null || maxLines > 0),
|
assert(maxLines == null || maxLines > 0),
|
||||||
super(key: key, curve: curve, duration: duration);
|
super(key: key, curve: curve, duration: duration, onEnd: onEnd);
|
||||||
|
|
||||||
/// The widget below this widget in the tree.
|
/// The widget below this widget in the tree.
|
||||||
///
|
///
|
||||||
@ -1484,6 +1510,7 @@ class AnimatedPhysicalModel extends ImplicitlyAnimatedWidget {
|
|||||||
this.animateShadowColor = true,
|
this.animateShadowColor = true,
|
||||||
Curve curve = Curves.linear,
|
Curve curve = Curves.linear,
|
||||||
@required Duration duration,
|
@required Duration duration,
|
||||||
|
VoidCallback onEnd,
|
||||||
}) : assert(child != null),
|
}) : assert(child != null),
|
||||||
assert(shape != null),
|
assert(shape != null),
|
||||||
assert(clipBehavior != null),
|
assert(clipBehavior != null),
|
||||||
@ -1493,7 +1520,7 @@ class AnimatedPhysicalModel extends ImplicitlyAnimatedWidget {
|
|||||||
assert(shadowColor != null),
|
assert(shadowColor != null),
|
||||||
assert(animateColor != null),
|
assert(animateColor != null),
|
||||||
assert(animateShadowColor != null),
|
assert(animateShadowColor != null),
|
||||||
super(key: key, curve: curve, duration: duration);
|
super(key: key, curve: curve, duration: duration, onEnd: onEnd);
|
||||||
|
|
||||||
/// The widget below this widget in the tree.
|
/// The widget below this widget in the tree.
|
||||||
///
|
///
|
||||||
|
@ -127,12 +127,12 @@ class TweenAnimationBuilder<T> extends ImplicitlyAnimatedWidget {
|
|||||||
@required Duration duration,
|
@required Duration duration,
|
||||||
Curve curve = Curves.linear,
|
Curve curve = Curves.linear,
|
||||||
@required this.builder,
|
@required this.builder,
|
||||||
this.onEnd,
|
VoidCallback onEnd,
|
||||||
this.child,
|
this.child,
|
||||||
}) : assert(tween != null),
|
}) : assert(tween != null),
|
||||||
assert(curve != null),
|
assert(curve != null),
|
||||||
assert(builder != null),
|
assert(builder != null),
|
||||||
super(key: key, duration: duration, curve: curve);
|
super(key: key, duration: duration, curve: curve, onEnd: onEnd);
|
||||||
|
|
||||||
/// Defines the target value for the animation.
|
/// Defines the target value for the animation.
|
||||||
///
|
///
|
||||||
@ -186,12 +186,6 @@ class TweenAnimationBuilder<T> extends ImplicitlyAnimatedWidget {
|
|||||||
/// performance significantly in some cases and is therefore a good practice.
|
/// performance significantly in some cases and is therefore a good practice.
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
/// 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
|
@override
|
||||||
ImplicitlyAnimatedWidgetState<ImplicitlyAnimatedWidget> createState() {
|
ImplicitlyAnimatedWidgetState<ImplicitlyAnimatedWidget> createState() {
|
||||||
return _TweenAnimationBuilderState<T>();
|
return _TweenAnimationBuilderState<T>();
|
||||||
@ -206,27 +200,11 @@ class _TweenAnimationBuilderState<T> extends AnimatedWidgetBaseState<TweenAnimat
|
|||||||
_currentTween = widget.tween;
|
_currentTween = widget.tween;
|
||||||
_currentTween.begin ??= _currentTween.end;
|
_currentTween.begin ??= _currentTween.end;
|
||||||
super.initState();
|
super.initState();
|
||||||
// The statusListener is removed when the superclass disposes the controller.
|
|
||||||
controller.addStatusListener(_onAnimationStatusChanged);
|
|
||||||
if (_currentTween.begin != _currentTween.end) {
|
if (_currentTween.begin != _currentTween.end) {
|
||||||
controller.forward();
|
controller.forward();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onAnimationStatusChanged(AnimationStatus status) {
|
|
||||||
switch (status) {
|
|
||||||
case AnimationStatus.dismissed:
|
|
||||||
case AnimationStatus.forward:
|
|
||||||
case AnimationStatus.reverse:
|
|
||||||
break;
|
|
||||||
case AnimationStatus.completed:
|
|
||||||
if (widget.onEnd != null) {
|
|
||||||
widget.onEnd();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void forEachTween(TweenVisitor<dynamic> visitor) {
|
void forEachTween(TweenVisitor<dynamic> visitor) {
|
||||||
assert(
|
assert(
|
||||||
|
@ -2,10 +2,29 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
class MockOnEndFunction implements Function {
|
||||||
|
int called = 0;
|
||||||
|
|
||||||
|
void call() {
|
||||||
|
called++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Duration animationDuration = Duration(milliseconds:1000);
|
||||||
|
const Duration additionalDelay = Duration(milliseconds:1);
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
MockOnEndFunction mockOnEndFunction;
|
||||||
|
const Key switchKey = Key('switchKey');
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
mockOnEndFunction = MockOnEndFunction();
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('BoxConstraintsTween control test', (WidgetTester tester) async {
|
testWidgets('BoxConstraintsTween control test', (WidgetTester tester) async {
|
||||||
final BoxConstraintsTween tween = BoxConstraintsTween(
|
final BoxConstraintsTween tween = BoxConstraintsTween(
|
||||||
begin: BoxConstraints.tight(const Size(20.0, 50.0)),
|
begin: BoxConstraints.tight(const Size(20.0, 50.0)),
|
||||||
@ -47,4 +66,355 @@ void main() {
|
|||||||
final Matrix4 result = tween.lerp(0.25);
|
final Matrix4 result = tween.lerp(0.25);
|
||||||
expect(result, equals(Matrix4.translationValues(11.0, 21.0, 31.0)));
|
expect(result, equals(Matrix4.translationValues(11.0, 21.0, 31.0)));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('AnimatedContainer onEnd callback test', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(wrap(
|
||||||
|
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedContainerWidgetState(),)
|
||||||
|
));
|
||||||
|
|
||||||
|
final Finder widgetFinder = find.byKey(switchKey);
|
||||||
|
|
||||||
|
await tester.tap(widgetFinder);
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(animationDuration);
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(additionalDelay);
|
||||||
|
expect(mockOnEndFunction.called, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('AnimatedPadding onEnd callback test', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(wrap(
|
||||||
|
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedPaddingWidgetState(),)
|
||||||
|
));
|
||||||
|
|
||||||
|
final Finder widgetFinder = find.byKey(switchKey);
|
||||||
|
|
||||||
|
await tester.tap(widgetFinder);
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(animationDuration);
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(additionalDelay);
|
||||||
|
expect(mockOnEndFunction.called, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('AnimatedAlign onEnd callback test', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(wrap(
|
||||||
|
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedAlignWidgetState(),)
|
||||||
|
));
|
||||||
|
|
||||||
|
final Finder widgetFinder = find.byKey(switchKey);
|
||||||
|
|
||||||
|
await tester.tap(widgetFinder);
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(animationDuration);
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(additionalDelay);
|
||||||
|
expect(mockOnEndFunction.called, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('AnimatedPositioned onEnd callback test', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(wrap(
|
||||||
|
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedPositionedWidgetState(),)
|
||||||
|
));
|
||||||
|
|
||||||
|
final Finder widgetFinder = find.byKey(switchKey);
|
||||||
|
|
||||||
|
await tester.tap(widgetFinder);
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(animationDuration);
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(additionalDelay);
|
||||||
|
expect(mockOnEndFunction.called, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('AnimatedPositionedDirectional onEnd callback test', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(wrap(
|
||||||
|
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedPositionedDirectionalWidgetState(),)
|
||||||
|
));
|
||||||
|
|
||||||
|
final Finder widgetFinder = find.byKey(switchKey);
|
||||||
|
|
||||||
|
await tester.tap(widgetFinder);
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(animationDuration);
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(additionalDelay);
|
||||||
|
expect(mockOnEndFunction.called, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('AnimatedOpacity onEnd callback test', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(wrap(
|
||||||
|
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedOpacityWidgetState(),)
|
||||||
|
));
|
||||||
|
|
||||||
|
final Finder widgetFinder = find.byKey(switchKey);
|
||||||
|
|
||||||
|
await tester.tap(widgetFinder);
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(animationDuration);
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(additionalDelay);
|
||||||
|
expect(mockOnEndFunction.called, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('AnimatedDefaultTextStyle onEnd callback test', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(wrap(
|
||||||
|
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedDefaultTextStyleWidgetState(),)
|
||||||
|
));
|
||||||
|
|
||||||
|
final Finder widgetFinder = find.byKey(switchKey);
|
||||||
|
|
||||||
|
await tester.tap(widgetFinder);
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(animationDuration);
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(additionalDelay);
|
||||||
|
expect(mockOnEndFunction.called, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('AnimatedPhysicalModel onEnd callback test', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(wrap(
|
||||||
|
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedPhysicalModelWidgetState(),)
|
||||||
|
));
|
||||||
|
|
||||||
|
final Finder widgetFinder = find.byKey(switchKey);
|
||||||
|
|
||||||
|
await tester.tap(widgetFinder);
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(animationDuration);
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(additionalDelay);
|
||||||
|
expect(mockOnEndFunction.called, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('TweenAnimationBuilder onEnd callback test', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(wrap(
|
||||||
|
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestTweenAnimationBuilderWidgetState(),)
|
||||||
|
));
|
||||||
|
|
||||||
|
final Finder widgetFinder = find.byKey(switchKey);
|
||||||
|
|
||||||
|
await tester.tap(widgetFinder);
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(animationDuration);
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(additionalDelay);
|
||||||
|
expect(mockOnEndFunction.called, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('AnimatedTheme onEnd callback test', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(wrap(
|
||||||
|
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedThemeWidgetState(),)
|
||||||
|
));
|
||||||
|
|
||||||
|
final Finder widgetFinder = find.byKey(switchKey);
|
||||||
|
|
||||||
|
await tester.tap(widgetFinder);
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(animationDuration);
|
||||||
|
expect(mockOnEndFunction.called, 0);
|
||||||
|
await tester.pump(additionalDelay);
|
||||||
|
expect(mockOnEndFunction.called, 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget wrap({Widget child}) {
|
||||||
|
return Directionality(
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
child: Material(
|
||||||
|
child: Center(child: child),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestAnimatedWidget extends StatefulWidget {
|
||||||
|
const TestAnimatedWidget({this.callback, this.switchKey, this.state});
|
||||||
|
@required
|
||||||
|
final VoidCallback callback;
|
||||||
|
@required
|
||||||
|
final Key switchKey;
|
||||||
|
@required
|
||||||
|
final State<StatefulWidget> state;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => state;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _TestAnimatedWidgetState extends State<TestAnimatedWidget> {
|
||||||
|
bool toggle = false;
|
||||||
|
final Widget child = const Placeholder();
|
||||||
|
final Duration duration = animationDuration;
|
||||||
|
|
||||||
|
void onChanged(bool v) {
|
||||||
|
setState(() {
|
||||||
|
toggle = v;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget getAnimatedWidget();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final Widget animatedWidget = getAnimatedWidget();
|
||||||
|
|
||||||
|
return Stack(
|
||||||
|
children: <Widget>[
|
||||||
|
animatedWidget,
|
||||||
|
Switch(key: widget.switchKey, value: toggle, onChanged: onChanged),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class _TestAnimatedContainerWidgetState extends _TestAnimatedWidgetState {
|
||||||
|
@override
|
||||||
|
Widget getAnimatedWidget() {
|
||||||
|
return AnimatedContainer(
|
||||||
|
child: child,
|
||||||
|
duration: duration,
|
||||||
|
onEnd: widget.callback,
|
||||||
|
width: toggle ? 10 : 20,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestAnimatedPaddingWidgetState extends _TestAnimatedWidgetState {
|
||||||
|
@override
|
||||||
|
Widget getAnimatedWidget() {
|
||||||
|
return AnimatedPadding(
|
||||||
|
child: child,
|
||||||
|
duration: duration,
|
||||||
|
onEnd: widget.callback,
|
||||||
|
padding:
|
||||||
|
toggle ? const EdgeInsets.all(8.0) : const EdgeInsets.all(16.0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestAnimatedAlignWidgetState extends _TestAnimatedWidgetState {
|
||||||
|
@override
|
||||||
|
Widget getAnimatedWidget() {
|
||||||
|
return AnimatedAlign(
|
||||||
|
child: child,
|
||||||
|
duration: duration,
|
||||||
|
onEnd: widget.callback,
|
||||||
|
alignment: toggle ? Alignment.topLeft : Alignment.bottomRight,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestAnimatedPositionedWidgetState extends _TestAnimatedWidgetState {
|
||||||
|
@override
|
||||||
|
Widget getAnimatedWidget() {
|
||||||
|
return AnimatedPositioned(
|
||||||
|
child: child,
|
||||||
|
duration: duration,
|
||||||
|
onEnd: widget.callback,
|
||||||
|
left: toggle ? 10 : 20,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestAnimatedPositionedDirectionalWidgetState extends _TestAnimatedWidgetState {
|
||||||
|
@override
|
||||||
|
Widget getAnimatedWidget() {
|
||||||
|
return AnimatedPositionedDirectional(
|
||||||
|
child: child,
|
||||||
|
duration: duration,
|
||||||
|
onEnd: widget.callback,
|
||||||
|
start: toggle ? 10 : 20,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestAnimatedOpacityWidgetState extends _TestAnimatedWidgetState {
|
||||||
|
@override
|
||||||
|
Widget getAnimatedWidget() {
|
||||||
|
return AnimatedOpacity(
|
||||||
|
child: child,
|
||||||
|
duration: duration,
|
||||||
|
onEnd: widget.callback,
|
||||||
|
opacity: toggle ? 0.1 : 0.9,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestAnimatedDefaultTextStyleWidgetState extends _TestAnimatedWidgetState {
|
||||||
|
@override
|
||||||
|
Widget getAnimatedWidget() {
|
||||||
|
return AnimatedDefaultTextStyle(
|
||||||
|
child: child,
|
||||||
|
duration: duration,
|
||||||
|
onEnd: widget.callback,
|
||||||
|
style: toggle
|
||||||
|
? const TextStyle(fontStyle: FontStyle.italic)
|
||||||
|
: const TextStyle(fontStyle: FontStyle.normal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestAnimatedPhysicalModelWidgetState extends _TestAnimatedWidgetState {
|
||||||
|
@override
|
||||||
|
Widget getAnimatedWidget() {
|
||||||
|
return AnimatedPhysicalModel(
|
||||||
|
child: child,
|
||||||
|
duration: duration,
|
||||||
|
onEnd: widget.callback,
|
||||||
|
color: toggle ? Colors.red : Colors.green,
|
||||||
|
elevation: 0,
|
||||||
|
shadowColor: Colors.blue,
|
||||||
|
shape: BoxShape.rectangle,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestTweenAnimationBuilderWidgetState extends _TestAnimatedWidgetState {
|
||||||
|
@override
|
||||||
|
Widget getAnimatedWidget() {
|
||||||
|
return TweenAnimationBuilder<double>(
|
||||||
|
child: child,
|
||||||
|
tween: Tween<double>(begin: 1, end: 2),
|
||||||
|
duration: duration,
|
||||||
|
onEnd: widget.callback,
|
||||||
|
builder: (BuildContext context, double size, Widget child) {
|
||||||
|
return Container(
|
||||||
|
child: child,
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TestAnimatedThemeWidgetState extends _TestAnimatedWidgetState {
|
||||||
|
@override
|
||||||
|
Widget getAnimatedWidget() {
|
||||||
|
return AnimatedTheme(
|
||||||
|
child: child,
|
||||||
|
data: toggle ? ThemeData.dark() : ThemeData.light(),
|
||||||
|
duration: duration,
|
||||||
|
onEnd: widget.callback,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user