@@ -92,6 +92,7 @@ class SemanticsData extends Diagnosticable {
92
92
@required this .decreasedValue,
93
93
@required this .hint,
94
94
@required this .textDirection,
95
+ @required this .nextNodeId,
95
96
@required this .previousNodeId,
96
97
@required this .rect,
97
98
@required this .textSelection,
@@ -151,6 +152,10 @@ class SemanticsData extends Diagnosticable {
151
152
/// [increasedValue] , and [decreasedValue] .
152
153
final TextDirection textDirection;
153
154
155
+ /// The index indicating the ID of the next node in the traversal order after
156
+ /// this node for the platform's accessibility services.
157
+ final int nextNodeId;
158
+
154
159
/// The index indicating the ID of the previous node in the traversal order before
155
160
/// this node for the platform's accessibility services.
156
161
final int previousNodeId;
@@ -237,6 +242,7 @@ class SemanticsData extends Diagnosticable {
237
242
properties.add (new StringProperty ('decreasedValue' , decreasedValue, defaultValue: '' ));
238
243
properties.add (new StringProperty ('hint' , hint, defaultValue: '' ));
239
244
properties.add (new EnumProperty <TextDirection >('textDirection' , textDirection, defaultValue: null ));
245
+ properties.add (new IntProperty ('nextNodeId' , nextNodeId, defaultValue: null ));
240
246
properties.add (new IntProperty ('previousNodeId' , previousNodeId, defaultValue: null ));
241
247
if (textSelection? .isValid == true )
242
248
properties.add (new MessageProperty ('textSelection' , '[${textSelection .start }, ${textSelection .end }]' ));
@@ -258,6 +264,7 @@ class SemanticsData extends Diagnosticable {
258
264
&& typedOther.decreasedValue == decreasedValue
259
265
&& typedOther.hint == hint
260
266
&& typedOther.textDirection == textDirection
267
+ && typedOther.nextNodeId == nextNodeId
261
268
&& typedOther.previousNodeId == previousNodeId
262
269
&& typedOther.rect == rect
263
270
&& setEquals (typedOther.tags, tags)
@@ -269,7 +276,7 @@ class SemanticsData extends Diagnosticable {
269
276
}
270
277
271
278
@override
272
- int get hashCode => ui.hashValues (flags, actions, label, value, increasedValue, decreasedValue, hint, textDirection, previousNodeId, rect, tags, textSelection, scrollPosition, scrollExtentMax, scrollExtentMin, transform);
279
+ int get hashCode => ui.hashValues (flags, actions, label, value, increasedValue, decreasedValue, hint, textDirection, nextNodeId, previousNodeId, rect, tags, textSelection, scrollPosition, scrollExtentMax, scrollExtentMin, transform);
273
280
}
274
281
275
282
class _SemanticsDiagnosticableNode extends DiagnosticableNode <SemanticsNode > {
@@ -1067,10 +1074,30 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
1067
1074
1068
1075
/// The sort order for ordering the traversal of [SemanticsNode] s by the
1069
1076
/// platform's accessibility services (e.g. VoiceOver on iOS and TalkBack on
1070
- /// Android). This is used to determine the [previousNodeId] during a semantics update.
1077
+ /// Android). This is used to determine the [nextNodeId] and [previousNodeId]
1078
+ /// during a semantics update.
1071
1079
SemanticsSortOrder _sortOrder;
1072
1080
SemanticsSortOrder get sortOrder => _sortOrder;
1073
1081
1082
+ /// The ID of the next node in the traversal order after this node.
1083
+ ///
1084
+ /// Only valid after at least one semantics update has been built.
1085
+ ///
1086
+ /// This is the value passed to the engine to tell it what the order
1087
+ /// should be for traversing semantics nodes.
1088
+ ///
1089
+ /// If this is set to -1, it will indicate that there is no next node to
1090
+ /// the engine (i.e. this is the last node in the sort order). When it is
1091
+ /// null, it means that no semantics update has been built yet.
1092
+ int _nextNodeId;
1093
+ void _updateNextNodeId (int value) {
1094
+ if (value == _nextNodeId)
1095
+ return ;
1096
+ _nextNodeId = value;
1097
+ _markDirty ();
1098
+ }
1099
+ int get nextNodeId => _nextNodeId;
1100
+
1074
1101
/// The ID of the previous node in the traversal order before this node.
1075
1102
///
1076
1103
/// Only valid after at least one semantics update has been built.
@@ -1194,6 +1221,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
1194
1221
String increasedValue = _increasedValue;
1195
1222
String decreasedValue = _decreasedValue;
1196
1223
TextDirection textDirection = _textDirection;
1224
+ int nextNodeId = _nextNodeId;
1197
1225
int previousNodeId = _previousNodeId;
1198
1226
Set <SemanticsTag > mergedTags = tags == null ? null : new Set <SemanticsTag >.from (tags);
1199
1227
TextSelection textSelection = _textSelection;
@@ -1207,6 +1235,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
1207
1235
flags | = node._flags;
1208
1236
actions | = node._actionsAsBits;
1209
1237
textDirection ?? = node._textDirection;
1238
+ nextNodeId ?? = node._nextNodeId;
1210
1239
previousNodeId ?? = node._previousNodeId;
1211
1240
textSelection ?? = node._textSelection;
1212
1241
scrollPosition ?? = node._scrollPosition;
@@ -1247,6 +1276,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
1247
1276
decreasedValue: decreasedValue,
1248
1277
hint: hint,
1249
1278
textDirection: textDirection,
1279
+ nextNodeId: nextNodeId,
1250
1280
previousNodeId: previousNodeId,
1251
1281
rect: rect,
1252
1282
transform: transform,
@@ -1289,6 +1319,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
1289
1319
increasedValue: data.increasedValue,
1290
1320
hint: data.hint,
1291
1321
textDirection: data.textDirection,
1322
+ nextNodeId: data.nextNodeId,
1292
1323
previousNodeId: data.previousNodeId,
1293
1324
textSelectionBase: data.textSelection != null ? data.textSelection.baseOffset : - 1 ,
1294
1325
textSelectionExtent: data.textSelection != null ? data.textSelection.extentOffset : - 1 ,
@@ -1363,6 +1394,7 @@ class SemanticsNode extends AbstractNode with DiagnosticableTreeMixin {
1363
1394
properties.add (new StringProperty ('decreasedValue' , _decreasedValue, defaultValue: '' ));
1364
1395
properties.add (new StringProperty ('hint' , _hint, defaultValue: '' ));
1365
1396
properties.add (new EnumProperty <TextDirection >('textDirection' , _textDirection, defaultValue: null ));
1397
+ properties.add (new IntProperty ('nextNodeId' , _nextNodeId, defaultValue: null ));
1366
1398
properties.add (new IntProperty ('previousNodeId' , _previousNodeId, defaultValue: null ));
1367
1399
properties.add (new DiagnosticsProperty <SemanticsSortOrder >('sortOrder' , sortOrder, defaultValue: null ));
1368
1400
if (_textSelection? .isValid == true )
@@ -1539,10 +1571,10 @@ class SemanticsOwner extends ChangeNotifier {
1539
1571
super .dispose ();
1540
1572
}
1541
1573
1542
- // Updates the previousNodeId IDs on the semantics nodes. These IDs are used
1543
- // on the platform side to order the nodes for traversal by the accessibility
1544
- // services. If the previousNodeId for a node changes, the node will be marked as
1545
- // dirty.
1574
+ // Updates the nextNodeId and previousNodeId IDs on the semantics nodes. These
1575
+ // IDs are used on the platform side to order the nodes for traversal by the
1576
+ // accessibility services. If the nextNodeId or previousNodeId for a node
1577
+ // changes, the node will be marked as dirty.
1546
1578
void _updateTraversalOrder () {
1547
1579
final List <_TraversalSortNode > nodesInSemanticsTraversalOrder = < _TraversalSortNode > [];
1548
1580
SemanticsSortOrder currentSortOrder = new SemanticsSortOrder (keys: < SemanticsSortKey > []);
@@ -1577,12 +1609,20 @@ class SemanticsOwner extends ChangeNotifier {
1577
1609
return true ;
1578
1610
}
1579
1611
rootSemanticsNode.visitChildren (visitor);
1612
+
1613
+ if (nodesInSemanticsTraversalOrder.isEmpty)
1614
+ return ;
1615
+
1580
1616
nodesInSemanticsTraversalOrder.sort ();
1581
- int previousNodeId = - 1 ;
1582
- for (_TraversalSortNode node in nodesInSemanticsTraversalOrder) {
1583
- node.node._updatePreviousNodeId (previousNodeId);
1584
- previousNodeId = node.node.id;
1617
+ _TraversalSortNode node = nodesInSemanticsTraversalOrder.removeLast ();
1618
+ node.node._updateNextNodeId (- 1 );
1619
+ while (nodesInSemanticsTraversalOrder.isNotEmpty) {
1620
+ final _TraversalSortNode previousNode = nodesInSemanticsTraversalOrder.removeLast ();
1621
+ node.node._updatePreviousNodeId (previousNode.node.id);
1622
+ previousNode.node._updateNextNodeId (node.node.id);
1623
+ node = previousNode;
1585
1624
}
1625
+ node.node._updatePreviousNodeId (- 1 );
1586
1626
}
1587
1627
1588
1628
/// Update the semantics using [Window.updateSemantics] .
0 commit comments