assembleSemanticsNode method
- @override
override
Assemble the SemanticsNode for this RenderObject.
If isSemanticBoundary
is true, this method is called with the node
created for this RenderObject, the config
to be applied to that node
and the children
SemanticNode
s that descendants of this RenderObject
have generated.
By default, the method will annotate node
with config
and add the
children
to it.
Subclasses can override this method to add additional SemanticsNodes to the tree. If new SemanticsNodes are instantiated in this method they must be disposed in clearSemantics.
Implementation
@override
void assembleSemanticsNode(SemanticsNode node, SemanticsConfiguration config, Iterable<SemanticsNode> children) {
assert(_recognizerOffsets.isNotEmpty);
assert(_recognizerOffsets.length.isEven);
assert(_recognizers.isNotEmpty);
assert(children.isEmpty);
final List<SemanticsNode> newChildren = <SemanticsNode>[];
final String rawLabel = text.toPlainText();
int current = 0;
double order = -1.0;
TextDirection currentDirection = textDirection;
Rect currentRect;
SemanticsConfiguration buildSemanticsConfig(int start, int end) {
final TextDirection initialDirection = currentDirection;
final TextSelection selection = TextSelection(baseOffset: start, extentOffset: end);
final List<ui.TextBox> rects = getBoxesForSelection(selection);
Rect rect;
for (ui.TextBox textBox in rects) {
rect ??= textBox.toRect();
rect = rect.expandToInclude(textBox.toRect());
currentDirection = textBox.direction;
}
// round the current rectangle to make this API testable and add some
// padding so that the accessibility rects do not overlap with the text.
// TODO(jonahwilliams): implement this for all text accessibility rects.
currentRect = Rect.fromLTRB(
rect.left.floorToDouble() - 4.0,
rect.top.floorToDouble() - 4.0,
rect.right.ceilToDouble() + 4.0,
rect.bottom.ceilToDouble() + 4.0,
);
order += 1;
return SemanticsConfiguration()
..sortKey = OrdinalSortKey(order)
..textDirection = initialDirection
..label = rawLabel.substring(start, end);
}
for (int i = 0, j = 0; i < _recognizerOffsets.length; i += 2, j++) {
final int start = _recognizerOffsets[i];
final int end = _recognizerOffsets[i + 1];
if (current != start) {
final SemanticsNode node = SemanticsNode();
final SemanticsConfiguration configuration = buildSemanticsConfig(current, start);
node.updateWith(config: configuration);
node.rect = currentRect;
newChildren.add(node);
}
final SemanticsNode node = SemanticsNode();
final SemanticsConfiguration configuration = buildSemanticsConfig(start, end);
final GestureRecognizer recognizer = _recognizers[j];
if (recognizer is TapGestureRecognizer) {
configuration.onTap = recognizer.onTap;
} else if (recognizer is LongPressGestureRecognizer) {
configuration.onLongPress = recognizer.onLongPress;
} else {
assert(false);
}
node.updateWith(config: configuration);
node.rect = currentRect;
newChildren.add(node);
current = end;
}
if (current < rawLabel.length) {
final SemanticsNode node = SemanticsNode();
final SemanticsConfiguration configuration = buildSemanticsConfig(current, rawLabel.length);
node.updateWith(config: configuration);
node.rect = currentRect;
newChildren.add(node);
}
node.updateWith(config: config, childrenInInversePaintOrder: newChildren);
}