From 6def1596cdbde87ebf78a2efefcdffc84951c4fa Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Tue, 12 Apr 2022 10:34:11 -0700 Subject: [PATCH] [framework] introduce repaint boundary in Opacity widgets (#101601) --- packages/flutter/lib/src/widgets/basic.dart | 51 +++++++++++++++---- .../lib/src/widgets/implicit_animations.dart | 4 +- .../flutter/lib/src/widgets/transitions.dart | 51 +++++++++++++++---- .../flutter/test/cupertino/nav_bar_test.dart | 2 +- .../flutter/test/material/debug_test.dart | 2 + 5 files changed, 88 insertions(+), 22 deletions(-) diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index 3be801a420..d7166272ec 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart @@ -242,7 +242,7 @@ class Directionality extends InheritedWidget { /// opacity. /// * [Image], which can directly provide a partially transparent image with /// much less performance hit. -class Opacity extends SingleChildRenderObjectWidget { +class Opacity extends StatelessWidget { /// Creates a widget that makes its child partially transparent. /// /// The [opacity] argument must not be null and must be between 0.0 and 1.0 @@ -251,10 +251,10 @@ class Opacity extends SingleChildRenderObjectWidget { Key? key, required this.opacity, this.alwaysIncludeSemantics = false, - Widget? child, + this.child, }) : assert(opacity != null && opacity >= 0.0 && opacity <= 1.0), assert(alwaysIncludeSemantics != null), - super(key: key, child: child); + super(key: key); /// The fraction to scale the child's alpha value. /// @@ -278,6 +278,44 @@ class Opacity extends SingleChildRenderObjectWidget { /// would otherwise contribute relevant semantics. final bool alwaysIncludeSemantics; + /// The widget below this widget in the tree. + /// + /// {@macro flutter.widgets.ProxyWidget.child} + final Widget? child; + + @override + Widget build(BuildContext context) { + return _Opacity( + opacity: opacity, + alwaysIncludeSemantics: alwaysIncludeSemantics, + child: RepaintBoundary( + child: child, + ), + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DoubleProperty('opacity', opacity)); + properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics')); + } +} + +/// The backing implementation of [Opacity]. +class _Opacity extends SingleChildRenderObjectWidget { + const _Opacity({ + Key? key, + required this.opacity, + this.alwaysIncludeSemantics = false, + Widget? child, + }) : assert(opacity != null && opacity >= 0.0 && opacity <= 1.0), + assert(alwaysIncludeSemantics != null), + super(key: key, child: child); + + final double opacity; + final bool alwaysIncludeSemantics; + @override RenderOpacity createRenderObject(BuildContext context) { return RenderOpacity( @@ -292,13 +330,6 @@ class Opacity extends SingleChildRenderObjectWidget { ..opacity = opacity ..alwaysIncludeSemantics = alwaysIncludeSemantics; } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DoubleProperty('opacity', opacity)); - properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics')); - } } /// A widget that applies a mask generated by a [Shader] to its child. diff --git a/packages/flutter/lib/src/widgets/implicit_animations.dart b/packages/flutter/lib/src/widgets/implicit_animations.dart index 9fba179614..3fe2aaa01a 100644 --- a/packages/flutter/lib/src/widgets/implicit_animations.dart +++ b/packages/flutter/lib/src/widgets/implicit_animations.dart @@ -1759,7 +1759,9 @@ class _AnimatedOpacityState extends ImplicitlyAnimatedWidgetState>('opacity', opacity)); + properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics')); + } +} + +/// The backing implementation of a [FadeTransition]. +class _FadeTransition extends SingleChildRenderObjectWidget { + const _FadeTransition({ + Key? key, + required this.opacity, + this.alwaysIncludeSemantics = false, + Widget? child, + }) : assert(opacity != null), + super(key: key, child: child); + + final Animation opacity; + + final bool alwaysIncludeSemantics; + @override RenderAnimatedOpacity createRenderObject(BuildContext context) { return RenderAnimatedOpacity( @@ -527,13 +565,6 @@ class FadeTransition extends SingleChildRenderObjectWidget { ..opacity = opacity ..alwaysIncludeSemantics = alwaysIncludeSemantics; } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty>('opacity', opacity)); - properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics')); - } } /// Animates the opacity of a sliver widget. diff --git a/packages/flutter/test/cupertino/nav_bar_test.dart b/packages/flutter/test/cupertino/nav_bar_test.dart index 12ea7cb47d..7f118be616 100644 --- a/packages/flutter/test/cupertino/nav_bar_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_test.dart @@ -951,7 +951,7 @@ void main() { ); await expectLater( - find.byType(RepaintBoundary).last, + find.byType(RepaintBoundary).first, matchesGoldenFile('nav_bar_test.large_title.png'), ); }, diff --git a/packages/flutter/test/material/debug_test.dart b/packages/flutter/test/material/debug_test.dart index 57a4b14688..f4d6ba4cca 100644 --- a/packages/flutter/test/material/debug_test.dart +++ b/packages/flutter/test/material/debug_test.dart @@ -128,6 +128,8 @@ void main() { ' RepaintBoundary-[GlobalKey#00000]\n' ' IgnorePointer\n' ' AnimatedBuilder\n' + ' RepaintBoundary\n' + ' _FadeTransition\n' ' FadeTransition\n' ' FractionalTranslation\n' ' SlideTransition\n'