sortDescendants method Null safety

  1. @override
Iterable<FocusNode> sortDescendants(
  1. Iterable<FocusNode> descendants,
  2. FocusNode currentNode
)
override

Sorts the given descendants into focus order.

Subclasses should override this to implement a different sort for next and previous to use in their ordering. If the returned iterable omits a node that is a descendant of the given scope, then the user will be unable to use next/previous keyboard traversal to reach that node.

The node used to initiate the traversal (the one passed to next or previous) is passed as currentNode.

Having the current node in the list is what allows the algorithm to determine which nodes are adjacent to the current node. If the currentNode is removed from the list, then the focus will be unchanged when next or previous are called, and they will return false.

This is not used for directional focus (inDirection), only for determining the focus order for next and previous.

When implementing an override for this function, be sure to use mergeSort instead of Dart's default list sorting algorithm when sorting items, since the default algorithm is not stable (items deemed to be equal can appear in arbitrary order, and change positions between sorts), whereas mergeSort is stable.

Implementation

@override
Iterable<FocusNode> sortDescendants(Iterable<FocusNode> descendants, FocusNode currentNode) {
  assert(descendants != null);
  if (descendants.length <= 1) {
    return descendants;
  }

  final List<_ReadingOrderSortData> data = <_ReadingOrderSortData>[
    for (final FocusNode node in descendants) _ReadingOrderSortData(node),
  ];

  final List<FocusNode> sortedList = <FocusNode>[];
  final List<_ReadingOrderSortData> unplaced = data;

  // Pick the initial widget as the one that is at the beginning of the band
  // of the topmost, or the topmost, if there are no others in its band.
  _ReadingOrderSortData current = _pickNext(unplaced);
  sortedList.add(current.node);
  unplaced.remove(current);

  // Go through each node, picking the next one after eliminating the previous
  // one, since removing the previously picked node will expose a new band in
  // which to choose candidates.
  while (unplaced.isNotEmpty) {
    final _ReadingOrderSortData next = _pickNext(unplaced);
    current = next;
    sortedList.add(current.node);
    unplaced.remove(current);
  }
  return sortedList;
}