TextField FocusNode attach location change
Summary
#EditableText.focusNode
is now attached to
a dedicated Focus
widget below EditableText
.
Context
#A text input field widget (TextField
, for example)
typically owns a FocusNode
.
When that FocusNode
is the primary focus of the app,
events (such as key presses) are sent to the BuildContext
to which the FocusNode
is attached.
The FocusNode
also plays a roll in shortcut handling:
The Shortcuts
widget translates key sequences into an Intent
, and
tries to find the first suitable handler for that Intent
starting from
the BuildContext
to which the FocusNode
is attached, to
the root of the widget tree. This means an Actions
widget (that provides
handlers for different Intent
s) won't be able to
handle any shortcut Intent
s when the BuildContext
that
has the primary focus is above it in the tree.
Previously for EditableText
, the FocusNode
was attached to
the BuildContext
of EditableTextState
.
Any Actions
widgets defined in EditableTextState
(which will be inflated
below the BuildContext
of the EditableTextState
) couldn't handle
shortcuts even when that EditableText
was focused, for
the reason stated above.
Description of change
#EditableTextState
now creates a dedicated Focus
widget to
host EditableText.focusNode
.
This allows EditableTextState
s to define handlers for shortcut Intent
s.
For instance, EditableText
now has a handler that
handles the "deleteCharacter" intent
when the DEL key is pressed.
This change does not involve any public API changes but
breaks codebases relying on that particular implementation detail to
tell if a FocusNode
is associated with a text input field.
This change does not break any builds but can introduce runtime issues, or cause existing tests to fail.
Migration guide
#The EditableText
widget takes a FocusNode
as a parameter, which was
previously attached to its EditableText
's BuildContext
. If you are relying
on runtime typecheck to find out if a FocusNode
is attached to a text input
field or a selectable text field like so:
focusNode.context.widget is EditableText
(focusNode.context as StatefulElement).state as EditableTextState
Then please read on and consider following the migration steps to avoid breakages.
If you're not sure whether a codebase needs migration,
search for is EditableText
, as EditableText
, is EditableTextState
, and
as EditableTextState
and verify if any of the search results are doing
a typecheck or typecast on a FocusNode.context
.
If so, then migration is needed.
To avoid performing a typecheck, or downcasting
the BuildContext
associated with the FocusNode
of interest, and
depending on the actual capabilities the codebase is trying to
invoke from the given FocusNode
, fire an Intent
from that BuildContext
.
For instance, if you wish to update the text of the currently focused
TextField
to a specific value, see the following example:
Code before migration:
final Widget? focusedWidget = primaryFocus?.context?.widget;
if (focusedWidget is EditableText) {
widget.controller.text = 'Updated Text';
}
Code after migration:
final BuildContext? focusedContext = primaryFocus?.context;
if (focusedContext != null) {
Actions.maybeInvoke(focusedContext, ReplaceTextIntent('UpdatedText'));
}
For a comprehensive list of Intent
s supported by the EditableText
widget,
refer to the documentation of the EditableText
widget.
Timeline
#Landed in version: 2.6.0-12.0.pre
In stable release: 2.10.0
References
#API documentation:
Relevant PR:
除非另有说明,本文档之所提及适用于 Flutter 的最新稳定版本,本页面最后更新时间: 2024-04-04。 查看文档源码 或者 为本页面内容提出建议.