Skip to content

Commit 6def159

Browse files
[framework] introduce repaint boundary in Opacity widgets (#101601)
1 parent 2d9e171 commit 6def159

File tree

5 files changed

+88
-22
lines changed

5 files changed

+88
-22
lines changed

packages/flutter/lib/src/widgets/basic.dart

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ class Directionality extends InheritedWidget {
242242
/// opacity.
243243
/// * [Image], which can directly provide a partially transparent image with
244244
/// much less performance hit.
245-
class Opacity extends SingleChildRenderObjectWidget {
245+
class Opacity extends StatelessWidget {
246246
/// Creates a widget that makes its child partially transparent.
247247
///
248248
/// The [opacity] argument must not be null and must be between 0.0 and 1.0
@@ -251,10 +251,10 @@ class Opacity extends SingleChildRenderObjectWidget {
251251
Key? key,
252252
required this.opacity,
253253
this.alwaysIncludeSemantics = false,
254-
Widget? child,
254+
this.child,
255255
}) : assert(opacity != null && opacity >= 0.0 && opacity <= 1.0),
256256
assert(alwaysIncludeSemantics != null),
257-
super(key: key, child: child);
257+
super(key: key);
258258

259259
/// The fraction to scale the child's alpha value.
260260
///
@@ -278,6 +278,44 @@ class Opacity extends SingleChildRenderObjectWidget {
278278
/// would otherwise contribute relevant semantics.
279279
final bool alwaysIncludeSemantics;
280280

281+
/// The widget below this widget in the tree.
282+
///
283+
/// {@macro flutter.widgets.ProxyWidget.child}
284+
final Widget? child;
285+
286+
@override
287+
Widget build(BuildContext context) {
288+
return _Opacity(
289+
opacity: opacity,
290+
alwaysIncludeSemantics: alwaysIncludeSemantics,
291+
child: RepaintBoundary(
292+
child: child,
293+
),
294+
);
295+
}
296+
297+
@override
298+
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
299+
super.debugFillProperties(properties);
300+
properties.add(DoubleProperty('opacity', opacity));
301+
properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics'));
302+
}
303+
}
304+
305+
/// The backing implementation of [Opacity].
306+
class _Opacity extends SingleChildRenderObjectWidget {
307+
const _Opacity({
308+
Key? key,
309+
required this.opacity,
310+
this.alwaysIncludeSemantics = false,
311+
Widget? child,
312+
}) : assert(opacity != null && opacity >= 0.0 && opacity <= 1.0),
313+
assert(alwaysIncludeSemantics != null),
314+
super(key: key, child: child);
315+
316+
final double opacity;
317+
final bool alwaysIncludeSemantics;
318+
281319
@override
282320
RenderOpacity createRenderObject(BuildContext context) {
283321
return RenderOpacity(
@@ -292,13 +330,6 @@ class Opacity extends SingleChildRenderObjectWidget {
292330
..opacity = opacity
293331
..alwaysIncludeSemantics = alwaysIncludeSemantics;
294332
}
295-
296-
@override
297-
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
298-
super.debugFillProperties(properties);
299-
properties.add(DoubleProperty('opacity', opacity));
300-
properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics'));
301-
}
302333
}
303334

304335
/// A widget that applies a mask generated by a [Shader] to its child.

packages/flutter/lib/src/widgets/implicit_animations.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1759,7 +1759,9 @@ class _AnimatedOpacityState extends ImplicitlyAnimatedWidgetState<AnimatedOpacit
17591759
return FadeTransition(
17601760
opacity: _opacityAnimation,
17611761
alwaysIncludeSemantics: widget.alwaysIncludeSemantics,
1762-
child: widget.child,
1762+
child: RepaintBoundary(
1763+
child: widget.child,
1764+
),
17631765
);
17641766
}
17651767
}

packages/flutter/lib/src/widgets/transitions.dart

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -483,17 +483,17 @@ class SizeTransition extends AnimatedWidget {
483483
/// * [Opacity], which does not animate changes in opacity.
484484
/// * [AnimatedOpacity], which animates changes in opacity without taking an
485485
/// explicit [Animation] argument.
486-
class FadeTransition extends SingleChildRenderObjectWidget {
486+
class FadeTransition extends StatelessWidget {
487487
/// Creates an opacity transition.
488488
///
489489
/// The [opacity] argument must not be null.
490490
const FadeTransition({
491491
Key? key,
492492
required this.opacity,
493493
this.alwaysIncludeSemantics = false,
494-
Widget? child,
494+
this.child,
495495
}) : assert(opacity != null),
496-
super(key: key, child: child);
496+
super(key: key);
497497

498498
/// The animation that controls the opacity of the child.
499499
///
@@ -513,6 +513,44 @@ class FadeTransition extends SingleChildRenderObjectWidget {
513513
/// would otherwise contribute relevant semantics.
514514
final bool alwaysIncludeSemantics;
515515

516+
/// The widget below this widget in the tree.
517+
///
518+
/// {@macro flutter.widgets.ProxyWidget.child}
519+
final Widget? child;
520+
521+
@override
522+
Widget build(BuildContext context) {
523+
return _FadeTransition(
524+
opacity: opacity,
525+
alwaysIncludeSemantics: alwaysIncludeSemantics,
526+
child: RepaintBoundary(
527+
child: child,
528+
),
529+
);
530+
}
531+
532+
@override
533+
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
534+
super.debugFillProperties(properties);
535+
properties.add(DiagnosticsProperty<Animation<double>>('opacity', opacity));
536+
properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics'));
537+
}
538+
}
539+
540+
/// The backing implementation of a [FadeTransition].
541+
class _FadeTransition extends SingleChildRenderObjectWidget {
542+
const _FadeTransition({
543+
Key? key,
544+
required this.opacity,
545+
this.alwaysIncludeSemantics = false,
546+
Widget? child,
547+
}) : assert(opacity != null),
548+
super(key: key, child: child);
549+
550+
final Animation<double> opacity;
551+
552+
final bool alwaysIncludeSemantics;
553+
516554
@override
517555
RenderAnimatedOpacity createRenderObject(BuildContext context) {
518556
return RenderAnimatedOpacity(
@@ -527,13 +565,6 @@ class FadeTransition extends SingleChildRenderObjectWidget {
527565
..opacity = opacity
528566
..alwaysIncludeSemantics = alwaysIncludeSemantics;
529567
}
530-
531-
@override
532-
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
533-
super.debugFillProperties(properties);
534-
properties.add(DiagnosticsProperty<Animation<double>>('opacity', opacity));
535-
properties.add(FlagProperty('alwaysIncludeSemantics', value: alwaysIncludeSemantics, ifTrue: 'alwaysIncludeSemantics'));
536-
}
537568
}
538569

539570
/// Animates the opacity of a sliver widget.

packages/flutter/test/cupertino/nav_bar_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,7 @@ void main() {
951951
);
952952

953953
await expectLater(
954-
find.byType(RepaintBoundary).last,
954+
find.byType(RepaintBoundary).first,
955955
matchesGoldenFile('nav_bar_test.large_title.png'),
956956
);
957957
},

packages/flutter/test/material/debug_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ void main() {
128128
' RepaintBoundary-[GlobalKey#00000]\n'
129129
' IgnorePointer\n'
130130
' AnimatedBuilder\n'
131+
' RepaintBoundary\n'
132+
' _FadeTransition\n'
131133
' FadeTransition\n'
132134
' FractionalTranslation\n'
133135
' SlideTransition\n'

0 commit comments

Comments
 (0)