unfocus method Null safety
- {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
.
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.
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}']));
}