mirror of
https://github.com/flutter/flutter
synced 2024-08-25 02:46:31 +00:00
Fix ParentDataWidget crash for multi view scenarios (#142486)
Fixes https://github.com/flutter/flutter/issues/142480. This fixes a crash occurring during hot reload when a `ViewAnchor` is used between a `ParentDataWidget` (like `Positioned`) and its closest `RenderObject` descendant. Prior to the fix, the `ParentDataWidget` was accidentally applying its parent data to the render object in the `ViewAnchor.view` slot, which crashed because that render object wasn't (and shouldn't be) setup to accept parent data (after all, it is in a different render tree). Instead, the parent data should only be applied to the render object in the `ViewAnchor.child` slot. Luckily, with `Element.renderObjectAttachingChild` we already have API in place to walk the widget tree such as that only `RenderObjectWidgets` from the same render tree are considered.
This commit is contained in:
parent
efca21c0fb
commit
3da5ff5490
|
@ -5855,11 +5855,13 @@ class ParentDataElement<T extends ParentData> extends ProxyElement {
|
|||
void applyParentDataToChild(Element child) {
|
||||
if (child is RenderObjectElement) {
|
||||
child._updateParentData(widget);
|
||||
} else {
|
||||
child.visitChildren(applyParentDataToChild);
|
||||
} else if (child.renderObjectAttachingChild != null) {
|
||||
applyParentDataToChild(child.renderObjectAttachingChild!);
|
||||
}
|
||||
}
|
||||
visitChildren(applyParentDataToChild);
|
||||
if (renderObjectAttachingChild != null) {
|
||||
applyParentDataToChild(renderObjectAttachingChild!);
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls [ParentDataWidget.applyParentData] on the given widget, passing it
|
||||
|
@ -6536,7 +6538,7 @@ abstract class RenderObjectElement extends Element {
|
|||
ErrorSummary('Incorrect use of ParentDataWidget.'),
|
||||
...parentDataWidget._debugDescribeIncorrectParentDataType(
|
||||
parentData: renderObject.parentData,
|
||||
parentDataCreator: _ancestorRenderObjectElement!.widget as RenderObjectWidget,
|
||||
parentDataCreator: _ancestorRenderObjectElement?.widget as RenderObjectWidget?,
|
||||
ownershipChain: ErrorDescription(debugGetCreatorChain(10)),
|
||||
),
|
||||
]);
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// 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/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'multi_view_testing.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Hot reload does not crash if ViewAnchor is used between ParentDataWidget and the render object it is applied to', (WidgetTester tester) async {
|
||||
// Regression test for https://github.com/flutter/flutter/issues/142480.
|
||||
Widget buildTest(String string) {
|
||||
return Directionality(
|
||||
textDirection: TextDirection.ltr,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Positioned( // ParentDataWidget
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: ViewAnchor(
|
||||
view: View(
|
||||
view: FakeView(tester.view),
|
||||
child: const Text('Side-view'),
|
||||
),
|
||||
child: Text(string), // Text's RenderObject is the target for the ParentDataWidget above.
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tester.pumpWidget(buildTest('bottom-right'));
|
||||
expect(tester.getBottomRight(find.text('bottom-right')), const Offset(800, 600));
|
||||
// Rebuild with a slightly different string to simulate a hot reload.
|
||||
await tester.pumpWidget(buildTest('bottom-right-again'));
|
||||
expect(find.text('bottom-right'), findsNothing);
|
||||
expect(tester.getBottomRight(find.text('bottom-right-again')), const Offset(800, 600));
|
||||
});
|
||||
}
|
Loading…
Reference in a new issue