Commit d4a01644 authored by Robin Jespersen's avatar Robin Jespersen Committed by Kate Lovett

Adding onEnd callback to implicit animated widgets (#38979)

parent 4373a319
...@@ -227,10 +227,11 @@ class AnimatedTheme extends ImplicitlyAnimatedWidget { ...@@ -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 { ...@@ -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 { ...@@ -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> ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 ...@@ -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 @@ ...@@ -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() { ...@@ -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,
);
}
} }
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