Skip to content

Commit d19047d

Browse files
[framework] make opacity widget create a repaint boundary (#116788)
1 parent 5a229e2 commit d19047d

File tree

2 files changed

+109
-14
lines changed

2 files changed

+109
-14
lines changed

packages/flutter/lib/src/rendering/proxy_box.dart

+13-14
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,9 @@ class RenderOpacity extends RenderProxyBox {
890890
@override
891891
bool get alwaysNeedsCompositing => child != null && _alpha > 0;
892892

893+
@override
894+
bool get isRepaintBoundary => alwaysNeedsCompositing;
895+
893896
int _alpha;
894897

895898
/// The fraction to scale the child's alpha value.
@@ -917,7 +920,7 @@ class RenderOpacity extends RenderProxyBox {
917920
if (didNeedCompositing != alwaysNeedsCompositing) {
918921
markNeedsCompositingBitsUpdate();
919922
}
920-
markNeedsPaint();
923+
markNeedsCompositedLayerUpdate();
921924
if (wasVisible != (_alpha != 0) && !alwaysIncludeSemantics) {
922925
markNeedsSemanticsUpdate();
923926
}
@@ -944,23 +947,19 @@ class RenderOpacity extends RenderProxyBox {
944947
return _alpha > 0;
945948
}
946949

950+
@override
951+
OffsetLayer updateCompositedLayer({required covariant OpacityLayer? oldLayer}) {
952+
final OpacityLayer layer = oldLayer ?? OpacityLayer();
953+
layer.alpha = _alpha;
954+
return layer;
955+
}
956+
947957
@override
948958
void paint(PaintingContext context, Offset offset) {
949-
if (child == null) {
950-
return;
951-
}
952-
if (_alpha == 0) {
953-
// No need to keep the layer. We'll create a new one if necessary.
954-
layer = null;
959+
if (child == null || _alpha == 0) {
955960
return;
956961
}
957-
958-
assert(needsCompositing);
959-
layer = context.pushOpacity(offset, _alpha, super.paint, oldLayer: layer as OpacityLayer?);
960-
assert(() {
961-
layer!.debugCreator = debugCreator;
962-
return true;
963-
}());
962+
super.paint(context, offset);
964963
}
965964

966965
@override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:flutter/material.dart';
6+
import 'package:flutter/rendering.dart';
7+
import 'package:flutter_test/flutter_test.dart';
8+
9+
void main() {
10+
testWidgets('RenderOpacity avoids repainting and does not drop layer at fully opaque', (WidgetTester tester) async {
11+
RenderTestObject.paintCount = 0;
12+
await tester.pumpWidget(
13+
Container(
14+
color: Colors.red,
15+
child: const Opacity(
16+
opacity: 0.0,
17+
child: TestWidget(),
18+
),
19+
)
20+
);
21+
22+
expect(RenderTestObject.paintCount, 0);
23+
24+
await tester.pumpWidget(
25+
Container(
26+
color: Colors.red,
27+
child: const Opacity(
28+
opacity: 0.1,
29+
child: TestWidget(),
30+
),
31+
)
32+
);
33+
34+
expect(RenderTestObject.paintCount, 1);
35+
36+
await tester.pumpWidget(
37+
Container(
38+
color: Colors.red,
39+
child: const Opacity(
40+
opacity: 1,
41+
child: TestWidget(),
42+
),
43+
)
44+
);
45+
46+
expect(RenderTestObject.paintCount, 1);
47+
});
48+
49+
testWidgets('RenderOpacity allows opacity layer to be dropped at 0 opacity', (WidgetTester tester) async {
50+
RenderTestObject.paintCount = 0;
51+
52+
await tester.pumpWidget(
53+
Container(
54+
color: Colors.red,
55+
child: const Opacity(
56+
opacity: 0.5,
57+
child: TestWidget(),
58+
),
59+
)
60+
);
61+
62+
expect(RenderTestObject.paintCount, 1);
63+
64+
await tester.pumpWidget(
65+
Container(
66+
color: Colors.red,
67+
child: const Opacity(
68+
opacity: 0.0,
69+
child: TestWidget(),
70+
),
71+
)
72+
);
73+
74+
expect(RenderTestObject.paintCount, 1);
75+
expect(tester.layers, isNot(contains(isA<OpacityLayer>())));
76+
});
77+
}
78+
79+
class TestWidget extends SingleChildRenderObjectWidget {
80+
const TestWidget({super.key, super.child});
81+
82+
@override
83+
RenderObject createRenderObject(BuildContext context) {
84+
return RenderTestObject();
85+
}
86+
}
87+
88+
class RenderTestObject extends RenderProxyBox {
89+
static int paintCount = 0;
90+
91+
@override
92+
void paint(PaintingContext context, Offset offset) {
93+
paintCount += 1;
94+
super.paint(context, offset);
95+
}
96+
}

0 commit comments

Comments
 (0)