Commit ecdfe658 authored by xster's avatar xster Committed by GitHub

Create DecoratedBoxTransition AnimatedWidget (#9369)

parent 8aacc288
......@@ -16,6 +16,10 @@ import 'image.dart';
/// not.
///
/// Commonly used with [BoxDecoration].
///
/// See also:
///
/// * [DecoratedBoxTransition], the version of this class that animates on the [decoration] property.
class DecoratedBox extends SingleChildRenderObjectWidget {
/// Creates a widget that paints a [Decoration].
///
......
......@@ -233,7 +233,8 @@ abstract class AnimatedWidgetBaseState<T extends ImplicitlyAnimatedWidget> exten
/// This class is useful for generating simple implicit transitions between
/// different parameters to [Container] with its internal
/// [AnimationController]. For more complex animations, you'll likely want to
/// use a subclass of [Transition] or use your own [AnimationController].
/// use a subclass of [Transition] such as the [DecoratedBoxTransition] or use
/// your own [AnimationController].
class AnimatedContainer extends ImplicitlyAnimatedWidget {
/// Creates a container that animates its parameters implicitly.
///
......
......@@ -8,6 +8,7 @@ import 'package:flutter/foundation.dart';
import 'package:vector_math/vector_math_64.dart' show Matrix4;
import 'basic.dart';
import 'container.dart';
import 'framework.dart';
export 'package:flutter/rendering.dart' show RelativeRect;
......@@ -388,6 +389,52 @@ class RelativePositionedTransition extends AnimatedWidget {
}
}
/// Animated version of a [DecoratedBox] that animates the different properties
/// of its [Decoration].
///
/// See also:
///
/// * [DecoratedBox], which also draws a [Decoration] but is not animated.
/// * [AnimatedContainer], a more full-featured container that also animates on
/// decoration using an internal animation.
class DecoratedBoxTransition extends AnimatedWidget {
/// Creates an animated [DecorationBox] whose [Decoration] animation updates
/// the widget.
///
/// The [decoration] and [position] cannot be null.
///
/// See also:
///
/// * [new DecoratedBox].
DecoratedBoxTransition({
Key key,
@required this.decoration,
this.position: DecorationPosition.background,
@required this.child,
}) : super(key: key, listenable: decoration);
/// Animation of the decoration to paint.
///
/// Can be created using a [DecorationTween] interpolating typically between
/// two [BoxDecoration].
final Animation<Decoration> decoration;
/// Whether to paint the box decoration behind or in front of the child.
final DecorationPosition position;
/// The widget below this widget in the tree.
final Widget child;
@override
Widget build(BuildContext context) {
return new DecoratedBox(
decoration: decoration.value,
position: position,
child: child,
);
}
}
/// A builder that builds a widget given a child.
///
/// The child should typically be part of the returned widget tree.
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
void main() {
......@@ -13,4 +14,132 @@ void main() {
);
expect(widget.toString, isNot(throwsException));
});
group('ContainerTransition test', () {
final DecorationTween decorationTween = new DecorationTween(
begin: new BoxDecoration(
backgroundColor: const Color(0xFFFFFFFF),
border: new Border.all(
color: const Color(0xFF000000),
style: BorderStyle.solid,
width: 4.0,
),
borderRadius: BorderRadius.zero,
shape: BoxShape.rectangle,
boxShadow: const <BoxShadow> [const BoxShadow(
color: const Color(0x66000000),
blurRadius: 10.0,
spreadRadius: 4.0,
)],
),
end: new BoxDecoration(
backgroundColor: const Color(0xFF000000),
border: new Border.all(
color: const Color(0xFF202020),
style: BorderStyle.solid,
width: 1.0,
),
borderRadius: new BorderRadius.circular(10.0),
shape: BoxShape.rectangle,
// No shadow.
),
);
AnimationController controller;
setUp(() {
controller = new AnimationController(vsync: const TestVSync());
});
testWidgets(
'decoration test',
(WidgetTester tester) async {
final DecoratedBoxTransition transitionUnderTest =
new DecoratedBoxTransition(
decoration: decorationTween.animate(controller),
child: const Text("Doesn't matter"),
);
await tester.pumpWidget(transitionUnderTest);
RenderDecoratedBox actualBox =
tester.renderObject(find.byType(DecoratedBox));
BoxDecoration actualDecoration = actualBox.decoration;
expect(actualDecoration.backgroundColor, const Color(0xFFFFFFFF));
expect(actualDecoration.boxShadow[0].blurRadius, 10.0);
expect(actualDecoration.boxShadow[0].spreadRadius, 4.0);
expect(actualDecoration.boxShadow[0].color, const Color(0x66000000));
controller.value = 0.5;
await tester.pump();
actualBox = tester.renderObject(find.byType(DecoratedBox));
actualDecoration = actualBox.decoration;
expect(actualDecoration.backgroundColor, const Color(0xFF7F7F7F));
expect(actualDecoration.border.left.width, 2.5);
expect(actualDecoration.border.left.style, BorderStyle.solid);
expect(actualDecoration.border.left.color, const Color(0xFF101010));
expect(actualDecoration.borderRadius, new BorderRadius.circular(5.0));
expect(actualDecoration.shape, BoxShape.rectangle);
expect(actualDecoration.boxShadow[0].blurRadius, 5.0);
expect(actualDecoration.boxShadow[0].spreadRadius, 2.0);
// Scaling a shadow doesn't change the color.
expect(actualDecoration.boxShadow[0].color, const Color(0x66000000));
controller.value = 1.0;
await tester.pump();
actualBox = tester.renderObject(find.byType(DecoratedBox));
actualDecoration = actualBox.decoration;
expect(actualDecoration.backgroundColor, const Color(0xFF000000));
expect(actualDecoration.boxShadow, null);
}
);
testWidgets('animations work with curves test', (WidgetTester tester) async {
final Animation<Decoration> curvedDecorationAnimation =
decorationTween.animate(new CurvedAnimation(
parent: controller,
curve: Curves.easeOut,
));
final DecoratedBoxTransition transitionUnderTest =
new DecoratedBoxTransition(
decoration: curvedDecorationAnimation,
position: DecorationPosition.foreground,
child: const Text("Doesn't matter"),
);
await tester.pumpWidget(transitionUnderTest);
RenderDecoratedBox actualBox =
tester.renderObject(find.byType(DecoratedBox));
BoxDecoration actualDecoration = actualBox.decoration;
expect(actualDecoration.backgroundColor, const Color(0xFFFFFFFF));
expect(actualDecoration.boxShadow[0].blurRadius, 10.0);
expect(actualDecoration.boxShadow[0].spreadRadius, 4.0);
expect(actualDecoration.boxShadow[0].color, const Color(0x66000000));
controller.value = 0.5;
await tester.pump();
actualBox = tester.renderObject(find.byType(DecoratedBox));
actualDecoration = actualBox.decoration;
// Same as the test above but the values should be much closer to the
// tween's end values given the easeOut curve.
expect(actualDecoration.backgroundColor, const Color(0xFF505050));
expect(actualDecoration.border.left.width, closeTo(1.9, 0.1));
expect(actualDecoration.border.left.style, BorderStyle.solid);
expect(actualDecoration.border.left.color, const Color(0xFF151515));
expect(actualDecoration.borderRadius.topLeft.x, closeTo(6.8, 0.1));
expect(actualDecoration.shape, BoxShape.rectangle);
expect(actualDecoration.boxShadow[0].blurRadius, closeTo(3.1, 0.1));
expect(actualDecoration.boxShadow[0].spreadRadius, closeTo(1.2, 0.1));
// Scaling a shadow doesn't change the color.
expect(actualDecoration.boxShadow[0].color, const Color(0x66000000));
});
});
}
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