unfocus method Null safety

void unfocus(
  1. {UnfocusDisposition disposition = UnfocusDisposition.scope}
)

Removes the focus on this node by moving the primary focus to another node.

This method removes focus from a node that has the primary focus, cancels any outstanding requests to focus it, while setting the primary focus to another node according to the disposition.

It is safe to call regardless of whether this node has ever requested focus or not. If this node doesn't have focus or primary focus, nothing happens.

The disposition argument determines which node will receive primary focus after this one loses it.

If disposition is set to UnfocusDisposition.scope (the default), then the previously focused node history of the enclosing scope will be cleared, and the primary focus will be moved to the nearest enclosing scope ancestor that is enabled for focus, ignoring the FocusScopeNode.focusedChild for that scope.

If disposition is set to UnfocusDisposition.previouslyFocusedChild, then this node will be removed from the previously focused list in the enclosingScope, and the focus will be moved to the previously focused node of the enclosingScope, which (if it is a scope itself), will find its focused child, etc., until a leaf focus node is found. If there is no previously focused child, then the scope itself will receive focus, as if UnfocusDisposition.scope were specified.

If you want this node to lose focus and the focus to move to the next or previous node in the enclosing FocusTraversalGroup, call nextFocus or previousFocus instead of calling unfocus.

This example shows the difference between the different UnfocusDisposition values for unfocus.

Try setting focus on the four text fields by selecting them, and then select "UNFOCUS" to see what happens when the current FocusManager.primaryFocus is unfocused.

Try pressing the TAB key after unfocusing to see what the next widget chosen is.

To create a local project with this code sample, run:
flutter create --sample=widgets.FocusNode.unfocus.1 mysample

Implementation

void unfocus({
  UnfocusDisposition disposition = UnfocusDisposition.scope,
}) {
  assert(disposition != null);
  if (!hasFocus && (_manager == null || _manager!._markedForFocus != this)) {
    return;
  }
  FocusScopeNode? scope = enclosingScope;
  if (scope == null) {
    // If the scope is null, then this is either the root node, or a node that
    // is not yet in the tree, neither of which do anything when unfocused.
    return;
  }
  switch (disposition) {
    case UnfocusDisposition.scope:
      // If it can't request focus, then don't modify its focused children.
      if (scope.canRequestFocus) {
        // Clearing the focused children here prevents re-focusing the node
        // that we just unfocused if we immediately hit "next" after
        // unfocusing, and also prevents choosing to refocus the next-to-last
        // focused child if unfocus is called more than once.
        scope._focusedChildren.clear();
      }

      while (!scope!.canRequestFocus) {
        scope = scope.enclosingScope ?? _manager?.rootScope;
      }
      scope._doRequestFocus(findFirstFocus: false);
      break;
    case UnfocusDisposition.previouslyFocusedChild:
      // Select the most recent focused child from the nearest focusable scope
      // and focus that. If there isn't one, focus the scope itself.
      if (scope.canRequestFocus) {
        scope._focusedChildren.remove(this);
      }
      while (!scope!.canRequestFocus) {
        scope.enclosingScope?._focusedChildren.remove(scope);
        scope = scope.enclosingScope ?? _manager?.rootScope;
      }
      scope._doRequestFocus(findFirstFocus: true);
      break;
  }
  assert(_focusDebug('Unfocused node:', <String>['primary focus was $this', 'next focus will be ${_manager?._markedForFocus}']));
}