Make Element tree root generic (#123352)
Make Element tree root generic
This commit is contained in:
parent
66e6acbe9f
commit
48bb12dfbe
@ -56,19 +56,19 @@ Future<void> main() async {
|
||||
|
||||
final Stopwatch watch = Stopwatch();
|
||||
|
||||
print('flutter_test allElements benchmark... (${WidgetsBinding.instance.renderViewElement})');
|
||||
print('flutter_test allElements benchmark... (${WidgetsBinding.instance.rootElement})');
|
||||
// Make sure we get enough elements to process for consistent benchmark runs
|
||||
int elementCount = collectAllElementsFrom(WidgetsBinding.instance.renderViewElement!, skipOffstage: false).length;
|
||||
int elementCount = collectAllElementsFrom(WidgetsBinding.instance.rootElement!, skipOffstage: false).length;
|
||||
while (elementCount < 2458) {
|
||||
await Future<void>.delayed(Duration.zero);
|
||||
elementCount = collectAllElementsFrom(WidgetsBinding.instance.renderViewElement!, skipOffstage: false).length;
|
||||
elementCount = collectAllElementsFrom(WidgetsBinding.instance.rootElement!, skipOffstage: false).length;
|
||||
}
|
||||
print('element count: $elementCount');
|
||||
|
||||
watch.start();
|
||||
for (int i = 0; i < _kNumIters; i += 1) {
|
||||
final List<Element> allElements = collectAllElementsFrom(
|
||||
WidgetsBinding.instance.renderViewElement!,
|
||||
WidgetsBinding.instance.rootElement!,
|
||||
skipOffstage: false,
|
||||
).toList();
|
||||
allElements.clear();
|
||||
|
@ -78,7 +78,7 @@ Future<void> smokeDemo(WidgetTester tester, GalleryDemo demo) async {
|
||||
|
||||
// Verify that the dumps are pretty.
|
||||
final String routeName = demo.routeName;
|
||||
verifyToStringOutput('debugDumpApp', routeName, WidgetsBinding.instance.renderViewElement!.toStringDeep());
|
||||
verifyToStringOutput('debugDumpApp', routeName, WidgetsBinding.instance.rootElement!.toStringDeep());
|
||||
verifyToStringOutput('debugDumpRenderTree', routeName, RendererBinding.instance.renderView.toStringDeep());
|
||||
verifyToStringOutput('debugDumpLayerTree', routeName, RendererBinding.instance.renderView.debugLayer?.toStringDeep() ?? '');
|
||||
|
||||
|
@ -23,6 +23,17 @@
|
||||
# * ListWheelScrollView: fix_list_wheel_scroll_view.yaml
|
||||
version: 1
|
||||
transforms:
|
||||
# Changes made in https://github.com/flutter/flutter/pull/123352
|
||||
- title: "Migrate to 'rootElement'"
|
||||
date: 2023-03-13
|
||||
element:
|
||||
uris: [ 'widgets.dart', 'material.dart', 'cupertino.dart' ]
|
||||
field: 'renderViewElement'
|
||||
inClass: 'WidgetsBinding'
|
||||
changes:
|
||||
- kind: 'rename'
|
||||
newName: 'rootElement'
|
||||
|
||||
# Changes made in https://github.com/flutter/flutter/pull/122555
|
||||
- title: "Migrate to 'decorationClipBehavior'"
|
||||
date: 2023-03-13
|
||||
|
@ -479,8 +479,8 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
|
||||
}
|
||||
|
||||
Future<void> _forceRebuild() {
|
||||
if (renderViewElement != null) {
|
||||
buildOwner!.reassemble(renderViewElement!, null);
|
||||
if (rootElement != null) {
|
||||
buildOwner!.reassemble(rootElement!, null);
|
||||
return endOfFrame;
|
||||
}
|
||||
return Future<void>.value();
|
||||
@ -889,8 +889,8 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
|
||||
}
|
||||
|
||||
try {
|
||||
if (renderViewElement != null) {
|
||||
buildOwner!.buildScope(renderViewElement!);
|
||||
if (rootElement != null) {
|
||||
buildOwner!.buildScope(rootElement!);
|
||||
}
|
||||
super.drawFrame();
|
||||
buildOwner!.finalizeTree();
|
||||
@ -914,12 +914,20 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
|
||||
}
|
||||
}
|
||||
|
||||
/// The [Element] that is at the root of the hierarchy (and which wraps the
|
||||
/// [RenderView] object at the root of the rendering hierarchy).
|
||||
/// The [Element] that is at the root of the element tree hierarchy.
|
||||
///
|
||||
/// This is initialized the first time [runApp] is called.
|
||||
Element? get renderViewElement => _renderViewElement;
|
||||
Element? _renderViewElement;
|
||||
Element? get rootElement => _rootElement;
|
||||
Element? _rootElement;
|
||||
|
||||
/// Deprecated. Will be removed in a future version of Flutter.
|
||||
///
|
||||
/// Use [rootElement] instead.
|
||||
@Deprecated(
|
||||
'Use rootElement instead. '
|
||||
'This feature was deprecated after v3.9.0-16.0.pre.'
|
||||
)
|
||||
Element? get renderViewElement => rootElement;
|
||||
|
||||
bool _readyToProduceFrames = false;
|
||||
|
||||
@ -951,7 +959,7 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
|
||||
});
|
||||
}
|
||||
|
||||
/// Takes a widget and attaches it to the [renderViewElement], creating it if
|
||||
/// Takes a widget and attaches it to the [rootElement], creating it if
|
||||
/// necessary.
|
||||
///
|
||||
/// This is called by [runApp] to configure the widget tree.
|
||||
@ -961,23 +969,23 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
|
||||
/// * [RenderObjectToWidgetAdapter.attachToRenderTree], which inflates a
|
||||
/// widget and attaches it to the render tree.
|
||||
void attachRootWidget(Widget rootWidget) {
|
||||
final bool isBootstrapFrame = renderViewElement == null;
|
||||
final bool isBootstrapFrame = rootElement == null;
|
||||
_readyToProduceFrames = true;
|
||||
_renderViewElement = RenderObjectToWidgetAdapter<RenderBox>(
|
||||
_rootElement = RenderObjectToWidgetAdapter<RenderBox>(
|
||||
container: renderView,
|
||||
debugShortDescription: '[root]',
|
||||
child: rootWidget,
|
||||
).attachToRenderTree(buildOwner!, renderViewElement as RenderObjectToWidgetElement<RenderBox>?);
|
||||
).attachToRenderTree(buildOwner!, rootElement as RenderObjectToWidgetElement<RenderBox>?);
|
||||
if (isBootstrapFrame) {
|
||||
SchedulerBinding.instance.ensureVisualUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the [renderViewElement] has been initialized.
|
||||
/// Whether the [rootElement] has been initialized.
|
||||
///
|
||||
/// This will be false until [runApp] is called (or [WidgetTester.pumpWidget]
|
||||
/// is called in the context of a [TestWidgetsFlutterBinding]).
|
||||
bool get isRootWidgetAttached => _renderViewElement != null;
|
||||
bool get isRootWidgetAttached => _rootElement != null;
|
||||
|
||||
@override
|
||||
Future<void> performReassemble() {
|
||||
@ -986,8 +994,8 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
|
||||
return true;
|
||||
}());
|
||||
|
||||
if (renderViewElement != null) {
|
||||
buildOwner!.reassemble(renderViewElement!, BindingBase.debugReassembleConfig);
|
||||
if (rootElement != null) {
|
||||
buildOwner!.reassemble(rootElement!, BindingBase.debugReassembleConfig);
|
||||
}
|
||||
return super.performReassemble();
|
||||
}
|
||||
@ -1069,8 +1077,8 @@ String _debugDumpAppString() {
|
||||
const String mode = kDebugMode ? 'DEBUG MODE' : kReleaseMode ? 'RELEASE MODE' : 'PROFILE MODE';
|
||||
final StringBuffer buffer = StringBuffer();
|
||||
buffer.writeln('${WidgetsBinding.instance.runtimeType} - $mode');
|
||||
if (WidgetsBinding.instance.renderViewElement != null) {
|
||||
buffer.writeln(WidgetsBinding.instance.renderViewElement!.toStringDeep());
|
||||
if (WidgetsBinding.instance.rootElement != null) {
|
||||
buffer.writeln(WidgetsBinding.instance.rootElement!.toStringDeep());
|
||||
} else {
|
||||
buffer.writeln('<no tree currently mounted>');
|
||||
}
|
||||
@ -1148,7 +1156,7 @@ class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWi
|
||||
String toStringShort() => debugShortDescription ?? super.toStringShort();
|
||||
}
|
||||
|
||||
/// A [RootRenderObjectElement] that is hosted by a [RenderObject].
|
||||
/// The root of the element tree that is hosted by a [RenderObject].
|
||||
///
|
||||
/// This element class is the instantiation of a [RenderObjectToWidgetAdapter]
|
||||
/// widget. It can be used only as the root of an [Element] tree (it cannot be
|
||||
@ -1158,7 +1166,7 @@ class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWi
|
||||
/// whose container is the [RenderView] that connects to the Flutter engine. In
|
||||
/// this usage, it is normally instantiated by the bootstrapping logic in the
|
||||
/// [WidgetsFlutterBinding] singleton created by [runApp].
|
||||
class RenderObjectToWidgetElement<T extends RenderObject> extends RootRenderObjectElement {
|
||||
class RenderObjectToWidgetElement<T extends RenderObject> extends RenderObjectElement with RootElementMixin {
|
||||
/// Creates an element that is hosted by a [RenderObject].
|
||||
///
|
||||
/// The [RenderObject] created by this element is not automatically set as a
|
||||
|
@ -2499,7 +2499,7 @@ abstract class BuildContext {
|
||||
/// Additional build owners can be built to manage off-screen widget trees.
|
||||
///
|
||||
/// To assign a build owner to a tree, use the
|
||||
/// [RootRenderObjectElement.assignOwner] method on the root element of the
|
||||
/// [RootElementMixin.assignOwner] method on the root element of the
|
||||
/// widget tree.
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
@ -6323,14 +6323,29 @@ abstract class RenderObjectElement extends Element {
|
||||
}
|
||||
}
|
||||
|
||||
/// The element at the root of the tree.
|
||||
/// Deprecated. Unused in the framework and will be removed in a future version
|
||||
/// of Flutter.
|
||||
///
|
||||
/// Classes that extend this class can extend [RenderObjectElement] and mixin
|
||||
/// [RootElementMixin] instead.
|
||||
@Deprecated(
|
||||
'Use RootElementMixin instead. '
|
||||
'This feature was deprecated after v3.9.0-16.0.pre.'
|
||||
)
|
||||
abstract class RootRenderObjectElement extends RenderObjectElement with RootElementMixin {
|
||||
/// Initializes fields for subclasses.
|
||||
@Deprecated(
|
||||
'Use RootElementMixin instead. '
|
||||
'This feature was deprecated after v3.9.0-16.0.pre.'
|
||||
)
|
||||
RootRenderObjectElement(super.widget);
|
||||
}
|
||||
|
||||
/// Mixin for the element at the root of the tree.
|
||||
///
|
||||
/// Only root elements may have their owner set explicitly. All other
|
||||
/// elements inherit their owner from their parent.
|
||||
abstract class RootRenderObjectElement extends RenderObjectElement {
|
||||
/// Initializes fields for subclasses.
|
||||
RootRenderObjectElement(super.widget);
|
||||
|
||||
mixin RootElementMixin on Element {
|
||||
/// Set the owner of the element. The owner will be propagated to all the
|
||||
/// descendants of this element.
|
||||
///
|
||||
|
@ -914,8 +914,8 @@ mixin WidgetInspectorService {
|
||||
@protected
|
||||
Future<void> forceRebuild() {
|
||||
final WidgetsBinding binding = WidgetsBinding.instance;
|
||||
if (binding.renderViewElement != null) {
|
||||
binding.buildOwner!.reassemble(binding.renderViewElement!, null);
|
||||
if (binding.rootElement != null) {
|
||||
binding.buildOwner!.reassemble(binding.rootElement!, null);
|
||||
return binding.endOfFrame;
|
||||
}
|
||||
return Future<void>.value();
|
||||
@ -1832,7 +1832,7 @@ mixin WidgetInspectorService {
|
||||
}
|
||||
|
||||
Map<String, Object?>? _getRootWidget(String groupName) {
|
||||
return _nodeToJson(WidgetsBinding.instance.renderViewElement?.toDiagnosticsNode(), InspectorSerializationDelegate(groupName: groupName, service: this));
|
||||
return _nodeToJson(WidgetsBinding.instance.rootElement?.toDiagnosticsNode(), InspectorSerializationDelegate(groupName: groupName, service: this));
|
||||
}
|
||||
|
||||
/// Returns a JSON representation of the [DiagnosticsNode] for the root
|
||||
@ -1846,7 +1846,7 @@ mixin WidgetInspectorService {
|
||||
Map<String, Object>? Function(DiagnosticsNode, InspectorSerializationDelegate)? addAdditionalPropertiesCallback,
|
||||
}) {
|
||||
return _nodeToJson(
|
||||
WidgetsBinding.instance.renderViewElement?.toDiagnosticsNode(),
|
||||
WidgetsBinding.instance.rootElement?.toDiagnosticsNode(),
|
||||
InspectorSerializationDelegate(
|
||||
groupName: groupName,
|
||||
subtreeDepth: 1000000,
|
||||
|
@ -17,34 +17,34 @@ void main() {
|
||||
expect(Fizz.count, 0);
|
||||
|
||||
DebugReassembleConfig config = DebugReassembleConfig(widgetName: 'Bar');
|
||||
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.renderViewElement!, config);
|
||||
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, config);
|
||||
|
||||
expect(Foo.count, 0);
|
||||
expect(Bar.count, 1);
|
||||
expect(Fizz.count, 1);
|
||||
|
||||
config = DebugReassembleConfig(widgetName: 'Fizz');
|
||||
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.renderViewElement!, config);
|
||||
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, config);
|
||||
|
||||
expect(Foo.count, 0);
|
||||
expect(Bar.count, 1);
|
||||
expect(Fizz.count, 2);
|
||||
|
||||
config = DebugReassembleConfig(widgetName: 'NoMatch');
|
||||
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.renderViewElement!, config);
|
||||
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, config);
|
||||
|
||||
expect(Foo.count, 0);
|
||||
expect(Bar.count, 1);
|
||||
expect(Fizz.count, 2);
|
||||
|
||||
config = DebugReassembleConfig();
|
||||
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.renderViewElement!, config);
|
||||
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, config);
|
||||
|
||||
expect(Foo.count, 1);
|
||||
expect(Bar.count, 2);
|
||||
expect(Fizz.count, 3);
|
||||
|
||||
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.renderViewElement!, null);
|
||||
WidgetsBinding.instance.buildOwner!.reassemble(WidgetsBinding.instance.rootElement!, null);
|
||||
|
||||
expect(Foo.count, 2);
|
||||
expect(Bar.count, 3);
|
||||
|
@ -58,7 +58,7 @@ class _TestLeafRenderObjectWidget extends LeafRenderObjectWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _TestElement extends RootRenderObjectElement{
|
||||
class _TestElement extends RenderObjectElement with RootElementMixin {
|
||||
_TestElement(): super(_TestLeafRenderObjectWidget());
|
||||
|
||||
void makeInactive() {
|
||||
|
@ -50,9 +50,9 @@ void main() {
|
||||
),
|
||||
);
|
||||
// Rendering tree is not built synchronously.
|
||||
expect(WidgetsBinding.instance.renderViewElement, isNull);
|
||||
expect(WidgetsBinding.instance.rootElement, isNull);
|
||||
fakeAsync.flushTimers();
|
||||
expect(WidgetsBinding.instance.renderViewElement, isNotNull);
|
||||
expect(WidgetsBinding.instance.rootElement, isNotNull);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -873,7 +873,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService {
|
||||
final List<Object?> chainElements = jsonList! as List<Object?>;
|
||||
final List<Element> expectedChain = elementB.debugGetDiagnosticChain().reversed.toList();
|
||||
// Sanity check that the chain goes back to the root.
|
||||
expect(expectedChain.first, tester.binding.renderViewElement);
|
||||
expect(expectedChain.first, tester.binding.rootElement);
|
||||
|
||||
expect(chainElements.length, equals(expectedChain.length));
|
||||
for (int i = 0; i < expectedChain.length; i += 1) {
|
||||
@ -2081,7 +2081,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService {
|
||||
final List<Object?> chainElements = jsonList! as List<Object?>;
|
||||
final List<Element> expectedChain = elementB.debugGetDiagnosticChain().reversed.toList();
|
||||
// Sanity check that the chain goes back to the root.
|
||||
expect(expectedChain.first, tester.binding.renderViewElement);
|
||||
expect(expectedChain.first, tester.binding.rootElement);
|
||||
|
||||
expect(chainElements.length, equals(expectedChain.length));
|
||||
for (int i = 0; i < expectedChain.length; i += 1) {
|
||||
@ -2327,7 +2327,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService {
|
||||
// directories so we get an empty tree other than the root that is always
|
||||
// included.
|
||||
final Object? rootWidget = service.toObject(rootJson['valueId']! as String);
|
||||
expect(rootWidget, equals(WidgetsBinding.instance.renderViewElement));
|
||||
expect(rootWidget, equals(WidgetsBinding.instance.rootElement));
|
||||
List<Object?> childrenJson = rootJson['children']! as List<Object?>;
|
||||
// There are no summary tree children.
|
||||
expect(childrenJson.length, equals(0));
|
||||
|
@ -106,8 +106,8 @@ class TestWidgetInspectorService extends Object with WidgetInspectorService {
|
||||
rebuildCount++;
|
||||
final WidgetsBinding binding = WidgetsBinding.instance;
|
||||
|
||||
if (binding.renderViewElement != null) {
|
||||
binding.buildOwner!.reassemble(binding.renderViewElement!, null);
|
||||
if (binding.rootElement != null) {
|
||||
binding.buildOwner!.reassemble(binding.rootElement!, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,9 @@ void main() {
|
||||
Object object;
|
||||
TickerProvider vsync;
|
||||
|
||||
// Changes made in https://github.com/flutter/flutter/pull/123352
|
||||
WidgetsBinding.instance.renderViewElement;
|
||||
|
||||
// Changes made in https://github.com/flutter/flutter/pull/119647
|
||||
MediaQueryData.fromWindow(View.of(context));
|
||||
|
||||
|
@ -12,6 +12,9 @@ void main() {
|
||||
Object object;
|
||||
TickerProvider vsync;
|
||||
|
||||
// Changes made in https://github.com/flutter/flutter/pull/123352
|
||||
WidgetsBinding.instance.rootElement;
|
||||
|
||||
// Changes made in https://github.com/flutter/flutter/pull/119647
|
||||
MediaQueryData.fromView(View.of(context));
|
||||
|
||||
|
@ -55,7 +55,7 @@ class _TestRenderObject extends RenderObject {
|
||||
Rect get semanticBounds => throw UnimplementedError();
|
||||
}
|
||||
|
||||
class _TestElement extends RootRenderObjectElement{
|
||||
class _TestElement extends RenderObjectElement with RootElementMixin {
|
||||
_TestElement(): super(_TestLeafRenderObjectWidget());
|
||||
|
||||
void makeInactive() {
|
||||
|
@ -57,7 +57,7 @@ class MatchesGoldenFile extends AsyncMatcher {
|
||||
final RenderObject renderObject = _findRepaintBoundary(element);
|
||||
final Size size = renderObject.paintBounds.size;
|
||||
final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.instance;
|
||||
final Element e = binding.renderViewElement!;
|
||||
final Element e = binding.rootElement!;
|
||||
final ui.FlutterView view = binding.platformDispatcher.implicitView!;
|
||||
|
||||
// Unlike `flutter_tester`, we don't have the ability to render an element
|
||||
|
@ -908,7 +908,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
// directly called again.
|
||||
DiagnosticsNode treeDump;
|
||||
try {
|
||||
treeDump = renderViewElement?.toDiagnosticsNode() ?? DiagnosticsNode.message('<no tree>');
|
||||
treeDump = rootElement?.toDiagnosticsNode() ?? DiagnosticsNode.message('<no tree>');
|
||||
// We try to stringify the tree dump here (though we immediately discard the result) because
|
||||
// we want to make sure that if it can't be serialised, we replace it with a message that
|
||||
// says the tree could not be serialised. Otherwise, the real exception might get obscured
|
||||
@ -1372,7 +1372,7 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
||||
assert(inTest);
|
||||
try {
|
||||
debugBuildingDirtyElements = true;
|
||||
buildOwner!.buildScope(renderViewElement!);
|
||||
buildOwner!.buildScope(rootElement!);
|
||||
if (_phase != EnginePhase.build) {
|
||||
pipelineOwner.flushLayout();
|
||||
if (_phase != EnginePhase.layout) {
|
||||
|
@ -379,7 +379,7 @@ abstract class WidgetController {
|
||||
/// using [Iterator.moveNext].
|
||||
Iterable<Element> get allElements {
|
||||
TestAsyncUtils.guardSync();
|
||||
return collectAllElementsFrom(binding.renderViewElement!, skipOffstage: false);
|
||||
return collectAllElementsFrom(binding.rootElement!, skipOffstage: false);
|
||||
}
|
||||
|
||||
/// The matching element in the widget tree.
|
||||
|
@ -493,7 +493,7 @@ abstract class Finder {
|
||||
@protected
|
||||
Iterable<Element> get allCandidates {
|
||||
return collectAllElementsFrom(
|
||||
WidgetsBinding.instance.renderViewElement!,
|
||||
WidgetsBinding.instance.rootElement!,
|
||||
skipOffstage: skipOffstage,
|
||||
);
|
||||
}
|
||||
|
@ -750,7 +750,7 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
|
||||
'your widget tree in a RootRestorationScope?',
|
||||
);
|
||||
return TestAsyncUtils.guard<void>(() async {
|
||||
final Widget widget = ((binding.renderViewElement! as RenderObjectToWidgetElement<RenderObject>).widget as RenderObjectToWidgetAdapter<RenderObject>).child!;
|
||||
final Widget widget = ((binding.rootElement! as RenderObjectToWidgetElement<RenderObject>).widget as RenderObjectToWidgetAdapter<RenderObject>).child!;
|
||||
final TestRestorationData restorationData = binding.restorationManager.restorationData;
|
||||
runApp(Container(key: UniqueKey()));
|
||||
await pump();
|
||||
@ -863,7 +863,7 @@ class WidgetTester extends WidgetController implements HitTestDispatcher, Ticker
|
||||
.whereType<RenderObject>()
|
||||
.first;
|
||||
final Element? innerTargetElement = _lastWhereOrNull(
|
||||
collectAllElementsFrom(binding.renderViewElement!, skipOffstage: true),
|
||||
collectAllElementsFrom(binding.rootElement!, skipOffstage: true),
|
||||
(Element element) => element.renderObject == innerTarget,
|
||||
);
|
||||
if (innerTargetElement == null) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user