FocusNode class

An object that can be used by a stateful widget to obtain the keyboard focus and to handle keyboard events.

Please see the Focus and FocusScope widgets, which are utility widgets that manage their own FocusNodes and FocusScopeNodes, respectively. If they aren't appropriate, FocusNodes can be managed directly, but doing this is rare.

FocusNodes are persistent objects that form a focus tree that is a representation of the widgets in the hierarchy that are interested in focus. A focus node might need to be created if it is passed in from an ancestor of a Focus widget to control the focus of the children from the ancestor, or a widget might need to host one if the widget subsystem is not being used, or if the Focus and FocusScope widgets provide insufficient control.

FocusNodes are organized into scopes (see FocusScopeNode), which form sub-trees of nodes that restrict traversal to a group of nodes. Within a scope, the most recent nodes to have focus are remembered, and if a node is focused and then unfocused, the previous node receives focus again.

The focus node hierarchy can be traversed using the parent, children, ancestors and descendants accessors.

FocusNodes are ChangeNotifiers, so a listener can be registered to receive a notification when the focus changes. Listeners will also be notified when skipTraversal, canRequestFocus, descendantsAreFocusable, and descendantsAreTraversable properties are updated. If the Focus and FocusScope widgets are being used to manage the nodes, consider establishing an InheritedWidget dependency on them by calling Focus.of or FocusScope.of instead. FocusNode.hasFocus can also be used to establish a similar dependency, especially if all that is needed is to determine whether or not the widget is focused at build time.

To see the focus tree in the debug console, call debugDumpFocusTree. To get the focus tree as a string, call debugDescribeFocusTree.

Lifecycle

There are several actors involved in the lifecycle of a FocusNode/FocusScopeNode. They are created and disposed by their owner, attached, detached, and re-parented using a FocusAttachment by their host (which must be owned by the State of a StatefulWidget), and they are managed by the FocusManager. Different parts of the FocusNode API are intended for these different actors.

FocusNodes (and hence FocusScopeNodes) are persistent objects that form part of a focus tree that is a sparse representation of the widgets in the hierarchy that are interested in receiving keyboard events. They must be managed like other persistent state, which is typically done by a StatefulWidget that owns the node. A stateful widget that owns a focus scope node must call dispose from its State.dispose method.

Once created, a FocusNode must be attached to the widget tree via a FocusAttachment object. This attachment is created by calling attach, usually from the State.initState method. If the hosting widget is updated to have a different focus node, then the updated node needs to be attached in State.didUpdateWidget, after calling FocusAttachment.detach on the previous FocusAttachment.

Because FocusNodes form a sparse representation of the widget tree, they must be updated whenever the widget tree is rebuilt. This is done by calling FocusAttachment.reparent, usually from the State.build or State.didChangeDependencies methods of the widget that represents the focused region, so that the BuildContext assigned to the FocusScopeNode can be tracked (the context is used to obtain the RenderObject, from which the geometry of focused regions can be determined).

Creating a FocusNode each time State.build is invoked will cause the focus to be lost each time the widget is built, which is usually not desired behavior (call unfocus if losing focus is desired).

If, as is common, the hosting StatefulWidget is also the owner of the focus node, then it will also call dispose from its State.dispose (in which case the FocusAttachment.detach may be skipped, since dispose will automatically detach). If another object owns the focus node, then it must call dispose when the node is done being used.

Key Event Propagation

The FocusManager receives key events from HardwareKeyboard and will pass them to the focused nodes. It starts with the node with the primary focus, and will call the onKeyEvent callback for that node. If the callback returns KeyEventResult.ignored, indicating that it did not handle the event, the FocusManager will move to the parent of that node and call its onKeyEvent. If that onKeyEvent returns KeyEventResult.handled, then it will stop propagating the event. If it reaches the root FocusScopeNode, FocusManager.rootScope, the event is discarded.

Focus Traversal

The term traversal, sometimes called tab traversal, refers to moving the focus from one widget to the next in a particular order (also sometimes referred to as the tab order, since the TAB key is often bound to the action to move to the next widget).

To give focus to the logical next or previous widget in the UI, call the nextFocus or previousFocus methods. To give the focus to a widget in a particular direction, call the focusInDirection method.

The policy for what the next or previous widget is, or the widget in a particular direction, is determined by the FocusTraversalPolicy in force.

The ambient policy is determined by looking up the widget hierarchy for a FocusTraversalGroup widget, and obtaining the focus traversal policy from it. Different focus nodes can inherit difference policies, so part of the app can go in a predefined order (using OrderedTraversalPolicy), and part can go in reading order (using ReadingOrderTraversalPolicy), depending upon the use case.

Predefined policies include WidgetOrderTraversalPolicy, ReadingOrderTraversalPolicy, OrderedTraversalPolicy, and DirectionalFocusTraversalPolicyMixin, but custom policies can be built based upon these policies. See FocusTraversalPolicy for more information.

This example shows how a FocusNode should be managed if not using the Focus or FocusScope widgets. See the Focus widget for a similar example using Focus and FocusScope widgets.
link

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

See also:

  • Focus, a widget that manages a FocusNode and provides access to focus information and actions to its descendant widgets.
  • FocusTraversalGroup, a widget used to group together and configure the focus traversal policy for a widget subtree.
  • FocusManager, a singleton that manages the primary focus and distributes key events to focused nodes.
  • FocusTraversalPolicy, a class used to determine how to move the focus to other nodes.
Mixed in types
Implementers

Constructors

FocusNode({String? debugLabel, @Deprecated('Use onKeyEvent instead. ' 'This feature was deprecated after v3.18.0-2.0.pre.') FocusOnKeyCallback? onKey, FocusOnKeyEventCallback? onKeyEvent, bool skipTraversal = false, bool canRequestFocus = true, bool descendantsAreFocusable = true, bool descendantsAreTraversable = true})
Creates a focus node.

Properties

ancestors Iterable<FocusNode>
An Iterable over the ancestors of this node.
no setter
canRequestFocus bool
If true, this focus node may request the primary focus.
getter/setter pair
children Iterable<FocusNode>
An iterator over the children of this node.
no setter
context BuildContext?
The context that was supplied to attach.
no setter
debugLabel String?
A debug label that is used for diagnostic output.
getter/setter pair
descendants Iterable<FocusNode>
An Iterable over the hierarchy of children below this one, in depth-first order.
no setter
descendantsAreFocusable bool
If false, will disable focus for all of this node's descendants.
getter/setter pair
descendantsAreTraversable bool
If false, tells the focus traversal policy to skip over for all of this node's descendants for purposes of the traversal algorithm.
getter/setter pair
enclosingScope FocusScopeNode?
Returns the nearest enclosing scope node above this node, or null if the node has not yet be added to the focus tree.
no setter
hasFocus bool
Whether this node has input focus.
no setter
hashCode int
The hash code for this object.
no setterinherited
hasListeners bool
Whether any listeners are currently registered.
no setterinherited
hasPrimaryFocus bool
Returns true if this node currently has the application-wide input focus.
no setter
highlightMode FocusHighlightMode
Returns the FocusHighlightMode that is currently in effect for this node.
no setter
nearestScope FocusScopeNode?
Returns the nearest enclosing scope node above this node, including this node, if it's a scope.
no setter
offset Offset
Returns the global offset to the upper left corner of the attached widget's RenderObject, in logical units.
no setter
onKey FocusOnKeyCallback?
Called if this focus node receives a key event while focused (i.e. when hasFocus returns true).
getter/setter pair
onKeyEvent FocusOnKeyEventCallback?
Called if this focus node receives a key event while focused (i.e. when hasFocus returns true).
getter/setter pair
parent FocusNode?
Returns the parent node for this object.
no setter
rect Rect
Returns the global rectangle of the attached widget's RenderObject, in logical units.
no setter
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
size Size
Returns the size of the attached widget's RenderObject, in logical units.
no setter
skipTraversal bool
If true, tells the focus traversal policy to skip over this node for purposes of the traversal algorithm.
getter/setter pair
traversalChildren Iterable<FocusNode>
An iterator over the children that are allowed to be traversed by the FocusTraversalPolicy.
no setter
traversalDescendants Iterable<FocusNode>
Returns all descendants which do not have the skipTraversal and do have the canRequestFocus flag set.
no setter

Methods

addListener(VoidCallback listener) → void
Register a closure to be called when the object changes.
inherited
attach(BuildContext? context, {FocusOnKeyEventCallback? onKeyEvent, FocusOnKeyCallback? onKey}) FocusAttachment
Called by the host StatefulWidget to attach a FocusNode to the widget tree.
consumeKeyboardToken() bool
Removes the keyboard token from this focus node if it has one.
debugDescribeChildren() List<DiagnosticsNode>
Returns a list of DiagnosticsNode objects describing this node's children.
override
debugFillProperties(DiagnosticPropertiesBuilder properties) → void
Add additional properties associated with the node.
override
dispose() → void
Discards any resources used by the object. After this is called, the object is not in a usable state and should be discarded (calls to addListener will throw after the object is disposed).
override
focusInDirection(TraversalDirection direction) bool
Request to move the focus to the nearest focus node in the given direction, by calling the FocusTraversalPolicy.inDirection method.
nextFocus() bool
Request to move the focus to the next focus node, by calling the FocusTraversalPolicy.next method.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
notifyListeners() → void
Call all the registered listeners.
inherited
previousFocus() bool
Request to move the focus to the previous focus node, by calling the FocusTraversalPolicy.previous method.
removeListener(VoidCallback listener) → void
Remove a previously registered closure from the list of closures that are notified when the object changes.
inherited
requestFocus([FocusNode? node]) → void
Requests the primary focus for this node, or for a supplied node, which will also give focus to its ancestors.
toDiagnosticsNode({String? name, DiagnosticsTreeStyle? style}) DiagnosticsNode
Returns a debug representation of the object that is used by debugging tools and by DiagnosticsNode.toStringDeep.
inherited
toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) String
A string representation of this object.
inherited
toStringDeep({String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug}) String
Returns a string representation of this node and its descendants.
inherited
toStringShallow({String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) String
Returns a one-line detailed description of the object.
inherited
toStringShort() String
A brief description of this object, usually just the runtimeType and the hashCode.
override
unfocus({UnfocusDisposition disposition = UnfocusDisposition.scope}) → void
Removes the focus on this node by moving the primary focus to another node.

Operators

operator ==(Object other) bool
The equality operator.
inherited