Commit 5ca4cc88 authored by Kate Lovett's avatar Kate Lovett Committed by Flutter GitHub Bot

Restored change (#48529)

parent 68d0c89f
...@@ -1293,6 +1293,8 @@ class _AnimatedPositionedDirectionalState extends AnimatedWidgetBaseState<Animat ...@@ -1293,6 +1293,8 @@ class _AnimatedPositionedDirectionalState extends AnimatedWidgetBaseState<Animat
/// * [AnimatedSwitcher], for fading between many children in sequence. /// * [AnimatedSwitcher], for fading between many children in sequence.
/// * [FadeTransition], an explicitly animated version of this widget, where /// * [FadeTransition], an explicitly animated version of this widget, where
/// an [Animation] is provided by the caller instead of being built in. /// an [Animation] is provided by the caller instead of being built in.
/// * [SliverAnimatedOpacity], for automatically transitioning a sliver's
/// opacity over a given duration whenever the given opacity changes.
class AnimatedOpacity extends ImplicitlyAnimatedWidget { class AnimatedOpacity extends ImplicitlyAnimatedWidget {
/// Creates a widget that animates its opacity implicitly. /// Creates a widget that animates its opacity implicitly.
/// ///
...@@ -1366,6 +1368,141 @@ class _AnimatedOpacityState extends ImplicitlyAnimatedWidgetState<AnimatedOpacit ...@@ -1366,6 +1368,141 @@ class _AnimatedOpacityState extends ImplicitlyAnimatedWidgetState<AnimatedOpacit
} }
} }
/// Animated version of [SliverOpacity] which automatically transitions the
/// sliver child's opacity over a given duration whenever the given opacity
/// changes.
///
/// Animating an opacity is relatively expensive because it requires painting
/// the sliver child into an intermediate buffer.
///
/// Here's an illustration of what using this widget looks like, using a [curve]
/// of [Curves.fastOutSlowIn].
///
/// {@animation 250 266 https://flutter.github.io/assets-for-api-docs/assets/widgets/animated_opacity.mp4}
///
/// {@tool sample --template=stateful_widget_scaffold_center_freeform_state}
/// Creates a [CustomScrollView] with a [SliverFixedExtentList] and a
/// [FloatingActionButton]. Pressing the button animates the lists' opacity.
///
/// ```dart
/// class _MyStatefulWidgetState extends State<MyStatefulWidget> with SingleTickerProviderStateMixin {
/// bool _visible = true;
///
/// Widget build(BuildContext context) {
/// return CustomScrollView(
/// slivers: <Widget>[
/// SliverAnimatedOpacity(
/// opacity: _visible ? 1.0 : 0.0,
/// duration: Duration(milliseconds: 500),
/// sliver: SliverFixedExtentList(
/// itemExtent: 100.0,
/// delegate: SliverChildBuilderDelegate(
/// (BuildContext context, int index) {
/// return Container(
/// color: index % 2 == 0
/// ? Colors.indigo[200]
/// : Colors.orange[200],
/// );
/// },
/// childCount: 5,
/// ),
/// ),
/// ),
/// SliverToBoxAdapter(
/// child: FloatingActionButton(
/// onPressed: () {
/// setState(() {
/// _visible = !_visible;
/// });
/// },
/// tooltip: 'Toggle opacity',
/// child: Icon(Icons.flip),
/// )
/// ),
/// ]
/// );
/// }
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [SliverFadeTransition], an explicitly animated version of this widget, where
/// an [Animation] is provided by the caller instead of being built in.
/// * [AnimatedOpacity], for automatically transitioning a box child's
/// opacity over a given duration whenever the given opacity changes.
class SliverAnimatedOpacity extends ImplicitlyAnimatedWidget {
/// Creates a widget that animates its opacity implicitly.
///
/// The [opacity] argument must not be null and must be between 0.0 and 1.0,
/// inclusive. The [curve] and [duration] arguments must not be null.
const SliverAnimatedOpacity({
Key key,
this.sliver,
@required this.opacity,
Curve curve = Curves.linear,
@required Duration duration,
VoidCallback onEnd,
this.alwaysIncludeSemantics = false,
}) : assert(opacity != null && opacity >= 0.0 && opacity <= 1.0),
super(key: key, curve: curve, duration: duration, onEnd: onEnd);
/// The sliver below this widget in the tree.
final Widget sliver;
/// The target opacity.
///
/// An opacity of 1.0 is fully opaque. An opacity of 0.0 is fully transparent
/// (i.e., invisible).
///
/// The opacity must not be null.
final double opacity;
/// Whether the semantic information of the children is always included.
///
/// Defaults to false.
///
/// When true, regardless of the opacity settings the sliver child's semantic
/// information is exposed as if the widget were fully visible. This is
/// useful in cases where labels may be hidden during animations that
/// would otherwise contribute relevant semantics.
final bool alwaysIncludeSemantics;
@override
_SliverAnimatedOpacityState createState() => _SliverAnimatedOpacityState();
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DoubleProperty('opacity', opacity));
}
}
class _SliverAnimatedOpacityState extends ImplicitlyAnimatedWidgetState<SliverAnimatedOpacity> {
Tween<double> _opacity;
Animation<double> _opacityAnimation;
@override
void forEachTween(TweenVisitor<dynamic> visitor) {
_opacity = visitor(_opacity, widget.opacity, (dynamic value) => Tween<double>(begin: value as double)) as Tween<double>;
}
@override
void didUpdateTweens() {
_opacityAnimation = animation.drive(_opacity);
}
@override
Widget build(BuildContext context) {
return SliverFadeTransition(
opacity: _opacityAnimation,
sliver: widget.sliver,
alwaysIncludeSemantics: widget.alwaysIncludeSemantics,
);
}
}
/// Animated version of [DefaultTextStyle] which automatically transitions the /// Animated version of [DefaultTextStyle] which automatically transitions the
/// default text style (the text style to apply to descendant [Text] widgets /// default text style (the text style to apply to descendant [Text] widgets
/// without explicit style) over a given duration whenever the given style /// without explicit style) over a given duration whenever the given style
......
...@@ -69,7 +69,11 @@ void main() { ...@@ -69,7 +69,11 @@ void main() {
testWidgets('AnimatedContainer onEnd callback test', (WidgetTester tester) async { testWidgets('AnimatedContainer onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(wrap( await tester.pumpWidget(wrap(
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedContainerWidgetState(),) child: TestAnimatedWidget(
callback: mockOnEndFunction,
switchKey: switchKey,
state: _TestAnimatedContainerWidgetState(),
)
)); ));
final Finder widgetFinder = find.byKey(switchKey); final Finder widgetFinder = find.byKey(switchKey);
...@@ -86,7 +90,11 @@ void main() { ...@@ -86,7 +90,11 @@ void main() {
testWidgets('AnimatedPadding onEnd callback test', (WidgetTester tester) async { testWidgets('AnimatedPadding onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(wrap( await tester.pumpWidget(wrap(
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedPaddingWidgetState(),) child: TestAnimatedWidget(
callback: mockOnEndFunction,
switchKey: switchKey,
state: _TestAnimatedPaddingWidgetState(),
)
)); ));
final Finder widgetFinder = find.byKey(switchKey); final Finder widgetFinder = find.byKey(switchKey);
...@@ -103,7 +111,11 @@ void main() { ...@@ -103,7 +111,11 @@ void main() {
testWidgets('AnimatedAlign onEnd callback test', (WidgetTester tester) async { testWidgets('AnimatedAlign onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(wrap( await tester.pumpWidget(wrap(
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedAlignWidgetState(),) child: TestAnimatedWidget(
callback: mockOnEndFunction,
switchKey: switchKey,
state: _TestAnimatedAlignWidgetState(),
)
)); ));
final Finder widgetFinder = find.byKey(switchKey); final Finder widgetFinder = find.byKey(switchKey);
...@@ -120,7 +132,11 @@ void main() { ...@@ -120,7 +132,11 @@ void main() {
testWidgets('AnimatedPositioned onEnd callback test', (WidgetTester tester) async { testWidgets('AnimatedPositioned onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(wrap( await tester.pumpWidget(wrap(
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedPositionedWidgetState(),) child: TestAnimatedWidget(
callback: mockOnEndFunction,
switchKey: switchKey,
state: _TestAnimatedPositionedWidgetState(),
)
)); ));
final Finder widgetFinder = find.byKey(switchKey); final Finder widgetFinder = find.byKey(switchKey);
...@@ -137,7 +153,11 @@ void main() { ...@@ -137,7 +153,11 @@ void main() {
testWidgets('AnimatedPositionedDirectional onEnd callback test', (WidgetTester tester) async { testWidgets('AnimatedPositionedDirectional onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(wrap( await tester.pumpWidget(wrap(
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedPositionedDirectionalWidgetState(),) child: TestAnimatedWidget(
callback: mockOnEndFunction,
switchKey: switchKey,
state: _TestAnimatedPositionedDirectionalWidgetState(),
)
)); ));
final Finder widgetFinder = find.byKey(switchKey); final Finder widgetFinder = find.byKey(switchKey);
...@@ -154,7 +174,58 @@ void main() { ...@@ -154,7 +174,58 @@ void main() {
testWidgets('AnimatedOpacity onEnd callback test', (WidgetTester tester) async { testWidgets('AnimatedOpacity onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(wrap( await tester.pumpWidget(wrap(
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedOpacityWidgetState(),) 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('AnimatedOpacity transition test', (WidgetTester tester) async {
await tester.pumpWidget(wrap(
child: TestAnimatedWidget(
switchKey: switchKey,
state: _TestAnimatedOpacityWidgetState(),
)
));
final Finder switchFinder = find.byKey(switchKey);
final FadeTransition opacityWidget = tester.widget<FadeTransition>(
find.ancestor(
of: find.byType(Placeholder),
matching: find.byType(FadeTransition),
).first,
);
await tester.tap(switchFinder);
await tester.pump();
expect(opacityWidget.opacity.value, equals(0.0));
await tester.pump(const Duration(milliseconds: 500));
expect(opacityWidget.opacity.value, equals(0.5));
await tester.pump(const Duration(milliseconds: 250));
expect(opacityWidget.opacity.value, equals(0.75));
await tester.pump(const Duration(milliseconds: 250));
expect(opacityWidget.opacity.value, equals(1.0));
});
testWidgets('SliverAnimatedOpacity onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(TestAnimatedWidget(
callback: mockOnEndFunction,
switchKey: switchKey,
state: _TestSliverAnimatedOpacityWidgetState(),
)); ));
final Finder widgetFinder = find.byKey(switchKey); final Finder widgetFinder = find.byKey(switchKey);
...@@ -169,9 +240,41 @@ void main() { ...@@ -169,9 +240,41 @@ void main() {
expect(mockOnEndFunction.called, 1); expect(mockOnEndFunction.called, 1);
}); });
testWidgets('SliverAnimatedOpacity transition test', (WidgetTester tester) async {
await tester.pumpWidget(wrap(
child: TestAnimatedWidget(
switchKey: switchKey,
state: _TestSliverAnimatedOpacityWidgetState(),
)
));
final Finder switchFinder = find.byKey(switchKey);
final SliverFadeTransition opacityWidget = tester.widget<SliverFadeTransition>(
find.ancestor(
of: find.byType(Placeholder),
matching: find.byType(SliverFadeTransition),
).first,
);
await tester.tap(switchFinder);
await tester.pump();
expect(opacityWidget.opacity.value, equals(0.0));
await tester.pump(const Duration(milliseconds: 500));
expect(opacityWidget.opacity.value, equals(0.5));
await tester.pump(const Duration(milliseconds: 250));
expect(opacityWidget.opacity.value, equals(0.75));
await tester.pump(const Duration(milliseconds: 250));
expect(opacityWidget.opacity.value, equals(1.0));
});
testWidgets('AnimatedDefaultTextStyle onEnd callback test', (WidgetTester tester) async { testWidgets('AnimatedDefaultTextStyle onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(wrap( await tester.pumpWidget(wrap(
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedDefaultTextStyleWidgetState(),) child: TestAnimatedWidget(
callback: mockOnEndFunction,
switchKey: switchKey,
state: _TestAnimatedDefaultTextStyleWidgetState(),
)
)); ));
final Finder widgetFinder = find.byKey(switchKey); final Finder widgetFinder = find.byKey(switchKey);
...@@ -188,7 +291,11 @@ void main() { ...@@ -188,7 +291,11 @@ void main() {
testWidgets('AnimatedPhysicalModel onEnd callback test', (WidgetTester tester) async { testWidgets('AnimatedPhysicalModel onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(wrap( await tester.pumpWidget(wrap(
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedPhysicalModelWidgetState(),) child: TestAnimatedWidget(
callback: mockOnEndFunction,
switchKey: switchKey,
state: _TestAnimatedPhysicalModelWidgetState(),
)
)); ));
final Finder widgetFinder = find.byKey(switchKey); final Finder widgetFinder = find.byKey(switchKey);
...@@ -205,7 +312,11 @@ void main() { ...@@ -205,7 +312,11 @@ void main() {
testWidgets('TweenAnimationBuilder onEnd callback test', (WidgetTester tester) async { testWidgets('TweenAnimationBuilder onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(wrap( await tester.pumpWidget(wrap(
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestTweenAnimationBuilderWidgetState(),) child: TestAnimatedWidget(
callback: mockOnEndFunction,
switchKey: switchKey,
state: _TestTweenAnimationBuilderWidgetState(),
)
)); ));
final Finder widgetFinder = find.byKey(switchKey); final Finder widgetFinder = find.byKey(switchKey);
...@@ -222,7 +333,11 @@ void main() { ...@@ -222,7 +333,11 @@ void main() {
testWidgets('AnimatedTheme onEnd callback test', (WidgetTester tester) async { testWidgets('AnimatedTheme onEnd callback test', (WidgetTester tester) async {
await tester.pumpWidget(wrap( await tester.pumpWidget(wrap(
child: TestAnimatedWidget(callback: mockOnEndFunction, switchKey: switchKey, state: _TestAnimatedThemeWidgetState(),) child: TestAnimatedWidget(
callback: mockOnEndFunction,
switchKey: switchKey,
state: _TestAnimatedThemeWidgetState(),
)
)); ));
final Finder widgetFinder = find.byKey(switchKey); final Finder widgetFinder = find.byKey(switchKey);
...@@ -360,7 +475,42 @@ class _TestAnimatedOpacityWidgetState extends _TestAnimatedWidgetState { ...@@ -360,7 +475,42 @@ class _TestAnimatedOpacityWidgetState extends _TestAnimatedWidgetState {
child: child, child: child,
duration: duration, duration: duration,
onEnd: widget.callback, onEnd: widget.callback,
opacity: toggle ? 0.1 : 0.9, opacity: toggle ? 1.0 : 0.0,
);
}
}
class _TestSliverAnimatedOpacityWidgetState extends _TestAnimatedWidgetState {
@override
Widget getAnimatedWidget() {
return SliverAnimatedOpacity(
sliver: SliverToBoxAdapter(child: child),
duration: duration,
onEnd: widget.callback,
opacity: toggle ? 1.0 : 0.0,
);
}
@override
Widget build(BuildContext context) {
final Widget animatedWidget = getAnimatedWidget();
return Material(
child: Directionality(
textDirection: TextDirection.ltr,
child: CustomScrollView(
slivers: <Widget>[
animatedWidget,
SliverToBoxAdapter(
child: Switch(
key: widget.switchKey,
value: toggle,
onChanged: onChanged,
),
),
],
),
),
); );
} }
} }
......
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