Skip to content

Commit 82afe3e

Browse files
authored
Clear the cached data of RenderBox if its parent re-layout (#101493)
1 parent 55881f7 commit 82afe3e

File tree

2 files changed

+87
-6
lines changed

2 files changed

+87
-6
lines changed

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

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,8 +2348,7 @@ abstract class RenderBox extends RenderObject {
23482348
}());
23492349
}
23502350

2351-
@override
2352-
void markNeedsLayout() {
2351+
bool _clearCachedData() {
23532352
if ((_cachedBaselines != null && _cachedBaselines!.isNotEmpty) ||
23542353
(_cachedIntrinsicDimensions != null && _cachedIntrinsicDimensions!.isNotEmpty) ||
23552354
(_cachedDryLayoutSizes != null && _cachedDryLayoutSizes!.isNotEmpty)) {
@@ -2361,14 +2360,30 @@ abstract class RenderBox extends RenderObject {
23612360
_cachedBaselines?.clear();
23622361
_cachedIntrinsicDimensions?.clear();
23632362
_cachedDryLayoutSizes?.clear();
2364-
if (parent is RenderObject) {
2365-
markParentNeedsLayout();
2366-
return;
2367-
}
2363+
return true;
2364+
}
2365+
return false;
2366+
}
2367+
2368+
@override
2369+
void markNeedsLayout() {
2370+
if (_clearCachedData() && parent is RenderObject) {
2371+
markParentNeedsLayout();
2372+
return;
23682373
}
23692374
super.markNeedsLayout();
23702375
}
23712376

2377+
@override
2378+
void layout(Constraints constraints, {bool parentUsesSize = false}) {
2379+
if (hasSize && constraints != this.constraints &&
2380+
_cachedBaselines != null && _cachedBaselines!.isNotEmpty) {
2381+
// The cached baselines data may need update if the constraints change.
2382+
_cachedBaselines?.clear();
2383+
}
2384+
super.layout(constraints, parentUsesSize: parentUsesSize);
2385+
}
2386+
23722387
/// {@macro flutter.rendering.RenderObject.performResize}
23732388
///
23742389
/// By default this method sets [size] to the result of [computeDryLayout]

packages/flutter/test/rendering/cached_intrinsics_test.dart

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
import 'package:flutter/rendering.dart';
66
import 'package:flutter_test/flutter_test.dart';
77

8+
import 'rendering_tester.dart';
9+
810
class RenderTestBox extends RenderBox {
11+
late Size boxSize;
12+
int calls = 0;
913
double value = 0.0;
1014
double next() {
1115
value += 1.0;
@@ -19,9 +23,23 @@ class RenderTestBox extends RenderBox {
1923
double computeMinIntrinsicHeight(double width) => next();
2024
@override
2125
double computeMaxIntrinsicHeight(double width) => next();
26+
27+
@override
28+
void performLayout() {
29+
size = constraints.biggest;
30+
boxSize = size;
31+
}
32+
33+
@override
34+
double? computeDistanceToActualBaseline(TextBaseline baseline) {
35+
calls += 1;
36+
return boxSize.height / 2.0;
37+
}
2238
}
2339

2440
void main() {
41+
TestRenderingFlutterBinding.ensureInitialized();
42+
2543
test('Intrinsics cache', () {
2644
final RenderBox test = RenderTestBox();
2745

@@ -68,4 +86,52 @@ void main() {
6886
expect(test.getMinIntrinsicWidth(0.0), equals(1.0));
6987

7088
});
89+
90+
// Regression test for https://github.com/flutter/flutter/issues/101179
91+
test('Cached baselines should be cleared if its parent re-layout', () {
92+
double viewHeight = 200.0;
93+
final RenderTestBox test = RenderTestBox();
94+
final RenderBox baseline = RenderBaseline(
95+
baseline: 0.0,
96+
baselineType: TextBaseline.alphabetic,
97+
child: test,
98+
);
99+
final RenderConstrainedBox root = RenderConstrainedBox(
100+
additionalConstraints: BoxConstraints.tightFor(width: 200.0, height: viewHeight),
101+
child: baseline,
102+
);
103+
104+
layout(RenderPositionedBox(
105+
child: root,
106+
));
107+
108+
BoxParentData? parentData = test.parentData as BoxParentData?;
109+
expect(parentData!.offset.dy, -(viewHeight / 2.0));
110+
expect(test.calls, 1);
111+
112+
// Trigger the root render re-layout.
113+
viewHeight = 300.0;
114+
root.additionalConstraints = BoxConstraints.tightFor(width: 200.0, height: viewHeight);
115+
pumpFrame();
116+
117+
parentData = test.parentData as BoxParentData?;
118+
expect(parentData!.offset.dy, -(viewHeight / 2.0));
119+
expect(test.calls, 2); // The layout constraints change will clear the cached data.
120+
121+
final RenderObject parent = test.parent! as RenderObject;
122+
expect(parent.debugNeedsLayout, false);
123+
124+
// Do not forget notify parent dirty after the cached data be cleared by `layout()`
125+
test.markNeedsLayout();
126+
expect(parent.debugNeedsLayout, true);
127+
128+
pumpFrame();
129+
expect(parent.debugNeedsLayout, false);
130+
expect(test.calls, 3); // Self dirty will clear the cached data.
131+
132+
parent.markNeedsLayout();
133+
pumpFrame();
134+
135+
expect(test.calls, 3); // Use the cached data if the layout constraints do not change.
136+
});
71137
}

0 commit comments

Comments
 (0)