Unverified Commit a63ee24b authored by LongCatIsLooong's avatar LongCatIsLooong Committed by GitHub

Reland "Avoid calling `performLayout` when only the relayout boundary is different" (#100581)

parent 2268aebb
......@@ -1629,7 +1629,16 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
assert(_debugSubtreeRelayoutRootAlreadyMarkedNeedsLayout());
return;
}
assert(_relayoutBoundary != null);
if (_relayoutBoundary == null) {
_needsLayout = true;
if (parent != null) {
// _relayoutBoundary is cleaned by an ancestor in RenderObject.layout.
// Conservatively mark everything dirty until it reaches the closest
// known relayout boundary.
markParentNeedsLayout();
}
return;
}
if (_relayoutBoundary != this) {
markParentNeedsLayout();
} else {
......@@ -1683,16 +1692,31 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
void _cleanRelayoutBoundary() {
if (_relayoutBoundary != this) {
_relayoutBoundary = null;
_needsLayout = true;
visitChildren(_cleanChildRelayoutBoundary);
}
}
void _propagateRelayoutBoundary() {
if (_relayoutBoundary == this) {
return;
}
final RenderObject? parentRelayoutBoundary = (parent as RenderObject?)?._relayoutBoundary;
assert(parentRelayoutBoundary != null);
if (parentRelayoutBoundary != _relayoutBoundary) {
_relayoutBoundary = parentRelayoutBoundary;
visitChildren(_propagateRelayoutBoundaryToChild);
}
}
// Reduces closure allocation for visitChildren use cases.
static void _cleanChildRelayoutBoundary(RenderObject child) {
child._cleanRelayoutBoundary();
}
static void _propagateRelayoutBoundaryToChild(RenderObject child) {
child._propagateRelayoutBoundary();
}
/// Bootstrap the rendering pipeline by scheduling the very first layout.
///
/// Requires this render object to be attached and that this render object
......@@ -1814,17 +1838,14 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
));
assert(!_debugDoingThisResize);
assert(!_debugDoingThisLayout);
RenderObject? relayoutBoundary;
if (!parentUsesSize || sizedByParent || constraints.isTight || parent is! RenderObject) {
relayoutBoundary = this;
} else {
relayoutBoundary = (parent! as RenderObject)._relayoutBoundary;
}
final bool isRelayoutBoundary = !parentUsesSize || sizedByParent || constraints.isTight || parent is! RenderObject;
final RenderObject relayoutBoundary = isRelayoutBoundary ? this : (parent! as RenderObject)._relayoutBoundary!;
assert(() {
_debugCanParentUseSize = parentUsesSize;
return true;
}());
if (!_needsLayout && constraints == _constraints && relayoutBoundary == _relayoutBoundary) {
if (!_needsLayout && constraints == _constraints) {
assert(() {
// in case parentUsesSize changed since the last invocation, set size
// to itself, so it has the right internal debug values.
......@@ -1839,6 +1860,11 @@ abstract class RenderObject extends AbstractNode with DiagnosticableTreeMixin im
return true;
}());
if (relayoutBoundary != _relayoutBoundary) {
_relayoutBoundary = relayoutBoundary;
visitChildren(_propagateRelayoutBoundaryToChild);
}
if (!kReleaseMode && debugProfileLayoutsEnabled)
Timeline.finishSync();
return;
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('relayout boundary change does not trigger relayout', (WidgetTester tester) async {
final RenderLayoutCount renderLayoutCount = RenderLayoutCount();
final Widget layoutCounter = Center(
key: GlobalKey(),
child: WidgetToRenderBoxAdapter(renderBox: renderLayoutCount),
);
await tester.pumpWidget(
Center(
child: SizedBox(
width: 100,
height: 100,
child: Center(
child: SizedBox(
width: 100,
height: 100,
child: Center(
child: layoutCounter,
),
),
),
),
),
);
expect(renderLayoutCount.layoutCount, 1);
await tester.pumpWidget(
Center(
child: SizedBox(
width: 100,
height: 100,
child: layoutCounter,
),
),
);
expect(renderLayoutCount.layoutCount, 1);
});
}
// This class is needed because LayoutBuilder's RenderObject does not always
// call the builder method in its PerformLayout method.
class RenderLayoutCount extends RenderBox {
int layoutCount = 0;
@override
void performLayout() {
layoutCount += 1;
size = constraints.biggest;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment