Update the semantics using ui.window.updateSemantics
.
Source
void sendSemanticsUpdate() { for (SemanticsNode oldNode in _detachedNodes) { // The other side will have forgotten this node if we even send // it again, so make sure to mark it dirty so that it'll get // sent if it is resurrected. oldNode._dirty = true; } _detachedNodes.clear(); if (_dirtyNodes.isEmpty) return; List<SemanticsNode> visitedNodes = <SemanticsNode>[]; while (_dirtyNodes.isNotEmpty) { List<SemanticsNode> localDirtyNodes = _dirtyNodes.toList(); _dirtyNodes.clear(); localDirtyNodes.sort((SemanticsNode a, SemanticsNode b) => a.depth - b.depth); visitedNodes.addAll(localDirtyNodes); for (SemanticsNode node in localDirtyNodes) { assert(node._dirty); assert(node.parent == null || !node.parent._shouldMergeAllDescendantsIntoThisNode || node._inheritedMergeAllDescendantsIntoThisNode); if (node._shouldMergeAllDescendantsIntoThisNode) { assert(node.mergeAllDescendantsIntoThisNode || node.parent != null); if (node.mergeAllDescendantsIntoThisNode || node.parent != null && node.parent._shouldMergeAllDescendantsIntoThisNode) { // if we're merged into our parent, make sure our parent is added to the list if (node.parent != null && node.parent._shouldMergeAllDescendantsIntoThisNode) node.parent._markDirty(); // this can add the node to the dirty list // make sure all the descendants are also marked, so that if one gets marked dirty later we know to walk up then too if (node._children != null) { for (SemanticsNode child in node._children) child._inheritedMergeAllDescendantsIntoThisNode = true; // this can add the node to the dirty list } } else { // we previously were being merged but aren't any more // update our bits and all our descendants' assert(node._inheritedMergeAllDescendantsIntoThisNode); assert(!node.mergeAllDescendantsIntoThisNode); assert(node.parent == null || !node.parent._shouldMergeAllDescendantsIntoThisNode); node._inheritedMergeAllDescendantsIntoThisNode = false; if (node._children != null) { for (SemanticsNode child in node._children) child._inheritedMergeAllDescendantsIntoThisNode = false; // this can add the node to the dirty list } } } } } visitedNodes.sort((SemanticsNode a, SemanticsNode b) => a.depth - b.depth); ui.SemanticsUpdateBuilder builder = new ui.SemanticsUpdateBuilder(); for (SemanticsNode node in visitedNodes) { assert(node.parent?._dirty != true); // could be null (no parent) or false (not dirty) // The _serialize() method marks the node as not dirty, and // recurses through the tree to do a deep serialization of all // contiguous dirty nodes. This means that when we return here, // it's quite possible that subsequent nodes are no longer // dirty. We skip these here. // We also skip any nodes that were reset and subsequently // dropped entirely (RenderObject.markNeedsSemanticsUpdate() // calls reset() on its SemanticsNode if onlyChanges isn't set, // which happens e.g. when the node is no longer contributing // semantics). if (node._dirty && node.attached) node._addToUpdate(builder); } _dirtyNodes.clear(); ui.window.updateSemantics(builder.build()); notifyListeners(); }