diff --git a/packages/flutter/lib/src/cupertino/context_menu.dart b/packages/flutter/lib/src/cupertino/context_menu.dart index 5fd7ebd1f9..619fec6dae 100644 --- a/packages/flutter/lib/src/cupertino/context_menu.dart +++ b/packages/flutter/lib/src/cupertino/context_menu.dart @@ -758,8 +758,8 @@ class _ContextMenuRoute extends PopupRoute { children: [ Positioned.fromRect( rect: sheetRect, - child: Opacity( - opacity: _sheetOpacity.value, + child: FadeTransition( + opacity: _sheetOpacity, child: Transform.scale( alignment: getSheetAlignment(_contextMenuLocation), scale: sheetScale, @@ -1028,8 +1028,8 @@ class _ContextMenuRouteStaticState extends State<_ContextMenuRouteStatic> with T return Transform.scale( alignment: _ContextMenuRoute.getSheetAlignment(widget.contextMenuLocation), scale: _sheetScaleAnimation.value, - child: Opacity( - opacity: _sheetOpacityAnimation.value, + child: FadeTransition( + opacity: _sheetOpacityAnimation, child: child, ), ); diff --git a/packages/flutter/lib/src/material/data_table.dart b/packages/flutter/lib/src/material/data_table.dart index 53f0a123c0..29e8acf488 100644 --- a/packages/flutter/lib/src/material/data_table.dart +++ b/packages/flutter/lib/src/material/data_table.dart @@ -1211,8 +1211,8 @@ class _SortArrowState extends State<_SortArrow> with TickerProviderStateMixin { @override Widget build(BuildContext context) { - return Opacity( - opacity: _opacityAnimation.value, + return FadeTransition( + opacity: _opacityAnimation, child: Transform( transform: Matrix4.rotationZ(_orientationOffset + _orientationAnimation.value) ..setTranslationRaw(0.0, _arrowIconBaselineOffset, 0.0), diff --git a/packages/flutter/lib/src/material/input_decorator.dart b/packages/flutter/lib/src/material/input_decorator.dart index 333fed6660..06bd59dc1c 100644 --- a/packages/flutter/lib/src/material/input_decorator.dart +++ b/packages/flutter/lib/src/material/input_decorator.dart @@ -373,8 +373,8 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta assert(widget.helperText != null); return Semantics( container: true, - child: Opacity( - opacity: 1.0 - _controller.value, + child: FadeTransition( + opacity: Tween(begin: 1.0, end: 0.0).animate(_controller), child: Text( widget.helperText!, style: widget.helperStyle, @@ -391,8 +391,8 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta return Semantics( container: true, liveRegion: true, - child: Opacity( - opacity: _controller.value, + child: FadeTransition( + opacity: _controller, child: FractionalTranslation( translation: Tween( begin: const Offset(0.0, -0.25), @@ -441,8 +441,8 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta if (widget.errorText != null) { return Stack( children: [ - Opacity( - opacity: 1.0 - _controller.value, + FadeTransition( + opacity: Tween(begin: 1.0, end: 0.0).animate(_controller), child: _helper, ), _buildError(), @@ -454,8 +454,8 @@ class _HelperErrorState extends State<_HelperError> with SingleTickerProviderSta return Stack( children: [ _buildHelper(), - Opacity( - opacity: _controller.value, + FadeTransition( + opacity: _controller, child: _error, ), ], diff --git a/packages/flutter/lib/src/material/navigation_rail.dart b/packages/flutter/lib/src/material/navigation_rail.dart index 760e7874c8..08815fccd5 100644 --- a/packages/flutter/lib/src/material/navigation_rail.dart +++ b/packages/flutter/lib/src/material/navigation_rail.dart @@ -573,6 +573,7 @@ class _RailDestination extends StatelessWidget { ), ); } else { + final Animation labelFadeAnimation = extendedTransitionAnimation.drive(CurveTween(curve: const Interval(0.0, 0.25))); content = Padding( padding: padding ?? EdgeInsets.zero, child: ConstrainedBox( @@ -587,9 +588,9 @@ class _RailDestination extends StatelessWidget { heightFactor: 1.0, widthFactor: extendedTransitionAnimation.value, alignment: AlignmentDirectional.centerStart, - child: Opacity( + child: FadeTransition( alwaysIncludeSemantics: true, - opacity: _extendedLabelFadeValue(), + opacity: labelFadeAnimation, child: styledLabel, ), ), @@ -604,6 +605,8 @@ class _RailDestination extends StatelessWidget { case NavigationRailLabelType.selected: final double appearingAnimationValue = 1 - _positionAnimation.value; final double verticalPadding = lerpDouble(_verticalDestinationPaddingNoLabel, _verticalDestinationPaddingWithLabel, appearingAnimationValue)!; + final Interval interval = selected ? const Interval(0.25, 0.75) : const Interval(0.75, 1.0); + final Animation labelFadeAnimation = destinationAnimation.drive(CurveTween(curve: interval)); content = Container( constraints: BoxConstraints( minWidth: minWidth, @@ -621,9 +624,9 @@ class _RailDestination extends StatelessWidget { alignment: Alignment.topCenter, heightFactor: appearingAnimationValue, widthFactor: 1.0, - child: Opacity( + child: FadeTransition( alwaysIncludeSemantics: true, - opacity: selected ? _normalLabelFadeInValue() : _normalLabelFadeOutValue(), + opacity: labelFadeAnimation, child: styledLabel, ), ), @@ -679,28 +682,6 @@ class _RailDestination extends StatelessWidget { ), ); } - - double _normalLabelFadeInValue() { - if (destinationAnimation.value < 0.25) { - return 0; - } else if (destinationAnimation.value < 0.75) { - return (destinationAnimation.value - 0.25) * 2; - } else { - return 1; - } - } - - double _normalLabelFadeOutValue() { - if (destinationAnimation.value > 0.75) { - return (destinationAnimation.value - 0.75) * 4.0; - } else { - return 0; - } - } - - double _extendedLabelFadeValue() { - return extendedTransitionAnimation.value < 0.25 ? extendedTransitionAnimation.value * 4.0 : 1.0; - } } /// Defines the behavior of the labels of a [NavigationRail]. diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index 1f9d92d4d6..ca6f64cfb8 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -596,8 +596,8 @@ class _PopupMenu extends StatelessWidget { return AnimatedBuilder( animation: route.animation!, builder: (BuildContext context, Widget? child) { - return Opacity( - opacity: opacity.evaluate(route.animation!), + return FadeTransition( + opacity: opacity.animate(route.animation!), child: Material( shape: route.shape ?? popupMenuTheme.shape, color: route.color ?? popupMenuTheme.color, diff --git a/packages/flutter/lib/src/widgets/heroes.dart b/packages/flutter/lib/src/widgets/heroes.dart index d213e5871f..95c4897592 100644 --- a/packages/flutter/lib/src/widgets/heroes.dart +++ b/packages/flutter/lib/src/widgets/heroes.dart @@ -547,8 +547,8 @@ class _HeroFlight { left: offsets.left, child: IgnorePointer( child: RepaintBoundary( - child: Opacity( - opacity: _heroOpacity.value, + child: FadeTransition( + opacity: _heroOpacity, child: child, ), ), diff --git a/packages/flutter/test/cupertino/nav_bar_transition_test.dart b/packages/flutter/test/cupertino/nav_bar_transition_test.dart index 93a1772f71..67cdfaf921 100644 --- a/packages/flutter/test/cupertino/nav_bar_transition_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_transition_test.dart @@ -117,7 +117,7 @@ void checkBackgroundBoxHeight(WidgetTester tester, double height) { void checkOpacity(WidgetTester tester, Finder finder, double opacity) { expect( - tester.renderObject( + tester.firstRenderObject( find.ancestor( of: finder, matching: find.byType(FadeTransition), diff --git a/packages/flutter/test/material/navigation_rail_test.dart b/packages/flutter/test/material/navigation_rail_test.dart index 2eb79d234d..f63531079b 100644 --- a/packages/flutter/test/material/navigation_rail_test.dart +++ b/packages/flutter/test/material/navigation_rail_test.dart @@ -2331,14 +2331,23 @@ Finder _opacityAboveLabel(String text) { } // Only valid when labelType != all. -double _labelOpacity(WidgetTester tester, String text) { - final Opacity opacityWidget = tester.widget( +double? _labelOpacity(WidgetTester tester, String text) { + // We search for both Opacity and FadeTransition since in some + // cases opacity is animated, in other it's not. + final Iterable opacityWidgets = tester.widgetList(find.ancestor( + of: find.text(text), + matching: find.byType(Opacity), + )); + if (opacityWidgets.isNotEmpty) + return opacityWidgets.single.opacity; + + final FadeTransition fadeTransitionWidget = tester.widget( find.ancestor( of: find.text(text), - matching: find.byType(Opacity), - ), + matching: find.byType(FadeTransition), + ).first, // first because there's also a FadeTransition from the MaterialPageRoute, which is up the tree ); - return opacityWidget.opacity; + return fadeTransitionWidget.opacity.value; } Material _railMaterial(WidgetTester tester) { diff --git a/packages/flutter/test/widgets/heroes_test.dart b/packages/flutter/test/widgets/heroes_test.dart index a4fb5ed409..99df4acf85 100644 --- a/packages/flutter/test/widgets/heroes_test.dart +++ b/packages/flutter/test/widgets/heroes_test.dart @@ -1182,7 +1182,7 @@ Future main() async { bool isVisible = true; node.visitAncestorElements((Element ancestor) { final RenderObject r = ancestor.renderObject!; - if (r is RenderOpacity && r.opacity == 0) { + if (r is RenderAnimatedOpacity && r.opacity.value == 0) { isVisible = false; return false; } @@ -2920,12 +2920,12 @@ Future main() async { final GlobalKey navigatorKey = GlobalKey(); final ScrollController controller = ScrollController(); - RenderOpacity? findRenderOpacity() { + RenderAnimatedOpacity? findRenderAnimatedOpacity() { AbstractNode? parent = tester.renderObject(find.byType(Placeholder)); - while (parent is RenderObject && parent is! RenderOpacity) { + while (parent is RenderObject && parent is! RenderAnimatedOpacity) { parent = parent.parent; } - return parent is RenderOpacity ? parent : null; + return parent is RenderAnimatedOpacity ? parent : null; } await tester.pumpWidget( @@ -2977,14 +2977,14 @@ Future main() async { // Starts Hero animation and scroll animation almost simultaneously. // Scroll to make the Hero invisible. await tester.pump(); - expect(findRenderOpacity()?.opacity, anyOf(isNull, 1.0)); + expect(findRenderAnimatedOpacity()?.opacity.value, anyOf(isNull, 1.0)); // In this frame the Hero animation finds out the toHero is not paintable, // and starts fading. await tester.pump(); await tester.pump(const Duration(milliseconds: 100)); - expect(findRenderOpacity()?.opacity, lessThan(1.0)); + expect(findRenderAnimatedOpacity()?.opacity.value, lessThan(1.0)); await tester.pumpAndSettle(); // The Hero on the new route should be invisible.