Restored change (#48529)
This commit is contained in:
parent
68d0c89ffc
commit
5ca4cc8852
@ -1293,6 +1293,8 @@ class _AnimatedPositionedDirectionalState extends AnimatedWidgetBaseState<Animat
|
||||
/// * [AnimatedSwitcher], for fading between many children in sequence.
|
||||
/// * [FadeTransition], an explicitly animated version of this widget, where
|
||||
/// 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 {
|
||||
/// Creates a widget that animates its opacity implicitly.
|
||||
///
|
||||
@ -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
|
||||
/// default text style (the text style to apply to descendant [Text] widgets
|
||||
/// without explicit style) over a given duration whenever the given style
|
||||
|
@ -69,7 +69,11 @@ void main() {
|
||||
|
||||
testWidgets('AnimatedContainer onEnd callback test', (WidgetTester tester) async {
|
||||
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);
|
||||
@ -86,7 +90,11 @@ void main() {
|
||||
|
||||
testWidgets('AnimatedPadding onEnd callback test', (WidgetTester tester) async {
|
||||
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);
|
||||
@ -103,7 +111,11 @@ void main() {
|
||||
|
||||
testWidgets('AnimatedAlign onEnd callback test', (WidgetTester tester) async {
|
||||
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);
|
||||
@ -120,7 +132,11 @@ void main() {
|
||||
|
||||
testWidgets('AnimatedPositioned onEnd callback test', (WidgetTester tester) async {
|
||||
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);
|
||||
@ -137,7 +153,11 @@ void main() {
|
||||
|
||||
testWidgets('AnimatedPositionedDirectional onEnd callback test', (WidgetTester tester) async {
|
||||
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);
|
||||
@ -154,7 +174,58 @@ void main() {
|
||||
|
||||
testWidgets('AnimatedOpacity onEnd callback test', (WidgetTester tester) async {
|
||||
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);
|
||||
@ -169,9 +240,41 @@ void main() {
|
||||
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 {
|
||||
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);
|
||||
@ -188,7 +291,11 @@ void main() {
|
||||
|
||||
testWidgets('AnimatedPhysicalModel onEnd callback test', (WidgetTester tester) async {
|
||||
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);
|
||||
@ -205,7 +312,11 @@ void main() {
|
||||
|
||||
testWidgets('TweenAnimationBuilder onEnd callback test', (WidgetTester tester) async {
|
||||
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);
|
||||
@ -222,7 +333,11 @@ void main() {
|
||||
|
||||
testWidgets('AnimatedTheme onEnd callback test', (WidgetTester tester) async {
|
||||
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);
|
||||
@ -360,7 +475,42 @@ class _TestAnimatedOpacityWidgetState extends _TestAnimatedWidgetState {
|
||||
child: child,
|
||||
duration: duration,
|
||||
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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -369,12 +519,12 @@ 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));
|
||||
child: child,
|
||||
duration: duration,
|
||||
onEnd: widget.callback,
|
||||
style: toggle
|
||||
? const TextStyle(fontStyle: FontStyle.italic)
|
||||
: const TextStyle(fontStyle: FontStyle.normal));
|
||||
}
|
||||
}
|
||||
|
||||
@ -397,17 +547,17 @@ 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,
|
||||
);
|
||||
},
|
||||
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,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user