如何正确聚焦根据焦点节点的 hasFocus 值有条件地创建的文本字段?
How can I correctly focus a Textfield that is conditionally created based on the focus node's hasFocus value?
使用我当前的代码,TextField 成为焦点,但未触发光标和键盘(需要第二次点击)。我认为这是因为最初聚焦节点时 TextField 不存在,但我正在努力寻找解决方案。
下面是基于 Cookbook 食谱的问题的简单重现:
class MyCustomForm extends StatefulWidget {
@override
_MyCustomFormState createState() => _MyCustomFormState();
}
class _MyCustomFormState extends State<MyCustomForm> {
FocusNode myFocusNode;
bool _editingField2 = false;
@override
void initState() {
super.initState();
myFocusNode = FocusNode();
myFocusNode.addListener(_focusListener);
}
@override
void dispose() {
myFocusNode.dispose();
super.dispose();
}
// Set _editingField2 to true when focusNode has focus.
_focusListener() {
if (myFocusNode.hasFocus) {
setState(() {
_editingField2 = true;
});
} else {
setState(() {
_editingField2 = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Text Field Focus'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// The first text field is focused on as soon as the app starts.
TextField(
autofocus: true,
),
// The second text field is created when _editingField2 (after FAB press).
_editingField2
? TextField(
focusNode: myFocusNode,
)
: Text('ayy'),
],
),
),
floatingActionButton: FloatingActionButton(
// Give focus node focus on FAB press.
onPressed: () => FocusScope.of(context).requestFocus(myFocusNode),
tooltip: 'Focus Second Text Field',
child: Icon(Icons.edit),
),
);
}
}
这是我的代码,对重要的部分进行了注释。
class TaskListItem extends StatefulWidget {
final Task task;
TaskListItem({@required this.task});
@override
State createState() => _TaskListItemState();
}
class _TaskListItemState extends State<TaskListItem> {
bool _isEditing;
FocusNode _focusNode;
final TextEditingController _textEditingController = TextEditingController();
@override
initState() {
super.initState();
_isEditing = false;
_textEditingController.text = widget.task.text;
_textEditingController.addListener(_handleTextFieldUpdate);
_focusNode = FocusNode(debugLabel: 'TaskListItem');
_focusNode.addListener(_handleFocusChange);
}
@override
void dispose() {
_focusNode.removeListener(_handleFocusChange);
_focusNode.dispose();
_textEditingController.dispose();
super.dispose();
}
_handleTextFieldUpdate() {
Provider.of<TaskListModel>(context, listen: false)
.updateTaskText(widget.task, _textEditingController.text);
}
// Update state to determine if Text or TextField widget is created in build().
_handleFocusChange() {
if (_focusNode.hasFocus) {
setState(() {
_isEditing = true;
});
} else {
setState(() {
_isEditing = false;
});
}
}
Widget _buildTitle() {
return Row(
children: <Widget>[
Expanded(
// Create either TextField or Text based on _isEditing value.
child: _isEditing && !widget.task.isComplete
? TextField(
focusNode: _focusNode,
controller: _textEditingController,
)
: Text(
widget.task.text,
style: widget.task.isComplete
? TextStyle(decoration: TextDecoration.lineThrough)
: null,
),
),
],
);
}
@override
Widget build(BuildContext context) {
return ListTile(
leading: Checkbox(
value: widget.task.isComplete,
//Dismiss focus when box is checked
onChanged: (bool checked) {
_focusNode.unfocus();
Provider.of<TaskListModel>(context, listen: false)
.toggleComplete(widget.task);
},
),
title: _buildTitle(),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => Provider.of<TaskListModel>(context, listen: false)
.deleteTask(widget.task),
),
onTap: () {
// I'm requesting focus here, but the Textfield doesn't exist yet?
FocusScope.of(context).requestFocus(_focusNode);
print('tapped');
},
);
}
}
您需要做的是在构建内部更改焦点,您正试图在屏幕完成重建该小部件之前更改焦点。请尝试使用您自己的代码。
我不确定您是否需要真正聆听焦点变化,或者您是否只想在启用小部件后完成焦点变化,如果您确实想要聆听焦点变化,请告诉我。
class MyCustomForm extends StatefulWidget {
@override
_MyCustomFormState createState() => _MyCustomFormState();
}
class _MyCustomFormState extends State<MyCustomForm> {
FocusNode myFocusNode = FocusNode();
bool _editingField2 = false;
@override
void dispose() {
myFocusNode?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
//here you do the focus request
if (_editingField2) {
FocusScope.of(context).requestFocus(myFocusNode);
}
return Scaffold(
appBar: AppBar(
title: Text('Text Field Focus'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// The first text field is focused on as soon as the app starts.
TextField(
autofocus: true,
),
// The second text field is created when _editingField2 (after FAB press).
_editingField2
? TextField(
focusNode: myFocusNode,
)
: Text('ayy'),
],
),
),
floatingActionButton: FloatingActionButton(
// Give focus node focus on FAB press.
onPressed: () {
setState(() {
_editingField2 = true;
});
},
tooltip: 'Focus Second Text Field',
child: Icon(Icons.edit),
),
);
}
}
使用我当前的代码,TextField 成为焦点,但未触发光标和键盘(需要第二次点击)。我认为这是因为最初聚焦节点时 TextField 不存在,但我正在努力寻找解决方案。
下面是基于 Cookbook 食谱的问题的简单重现:
class MyCustomForm extends StatefulWidget {
@override
_MyCustomFormState createState() => _MyCustomFormState();
}
class _MyCustomFormState extends State<MyCustomForm> {
FocusNode myFocusNode;
bool _editingField2 = false;
@override
void initState() {
super.initState();
myFocusNode = FocusNode();
myFocusNode.addListener(_focusListener);
}
@override
void dispose() {
myFocusNode.dispose();
super.dispose();
}
// Set _editingField2 to true when focusNode has focus.
_focusListener() {
if (myFocusNode.hasFocus) {
setState(() {
_editingField2 = true;
});
} else {
setState(() {
_editingField2 = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Text Field Focus'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// The first text field is focused on as soon as the app starts.
TextField(
autofocus: true,
),
// The second text field is created when _editingField2 (after FAB press).
_editingField2
? TextField(
focusNode: myFocusNode,
)
: Text('ayy'),
],
),
),
floatingActionButton: FloatingActionButton(
// Give focus node focus on FAB press.
onPressed: () => FocusScope.of(context).requestFocus(myFocusNode),
tooltip: 'Focus Second Text Field',
child: Icon(Icons.edit),
),
);
}
}
这是我的代码,对重要的部分进行了注释。
class TaskListItem extends StatefulWidget {
final Task task;
TaskListItem({@required this.task});
@override
State createState() => _TaskListItemState();
}
class _TaskListItemState extends State<TaskListItem> {
bool _isEditing;
FocusNode _focusNode;
final TextEditingController _textEditingController = TextEditingController();
@override
initState() {
super.initState();
_isEditing = false;
_textEditingController.text = widget.task.text;
_textEditingController.addListener(_handleTextFieldUpdate);
_focusNode = FocusNode(debugLabel: 'TaskListItem');
_focusNode.addListener(_handleFocusChange);
}
@override
void dispose() {
_focusNode.removeListener(_handleFocusChange);
_focusNode.dispose();
_textEditingController.dispose();
super.dispose();
}
_handleTextFieldUpdate() {
Provider.of<TaskListModel>(context, listen: false)
.updateTaskText(widget.task, _textEditingController.text);
}
// Update state to determine if Text or TextField widget is created in build().
_handleFocusChange() {
if (_focusNode.hasFocus) {
setState(() {
_isEditing = true;
});
} else {
setState(() {
_isEditing = false;
});
}
}
Widget _buildTitle() {
return Row(
children: <Widget>[
Expanded(
// Create either TextField or Text based on _isEditing value.
child: _isEditing && !widget.task.isComplete
? TextField(
focusNode: _focusNode,
controller: _textEditingController,
)
: Text(
widget.task.text,
style: widget.task.isComplete
? TextStyle(decoration: TextDecoration.lineThrough)
: null,
),
),
],
);
}
@override
Widget build(BuildContext context) {
return ListTile(
leading: Checkbox(
value: widget.task.isComplete,
//Dismiss focus when box is checked
onChanged: (bool checked) {
_focusNode.unfocus();
Provider.of<TaskListModel>(context, listen: false)
.toggleComplete(widget.task);
},
),
title: _buildTitle(),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () => Provider.of<TaskListModel>(context, listen: false)
.deleteTask(widget.task),
),
onTap: () {
// I'm requesting focus here, but the Textfield doesn't exist yet?
FocusScope.of(context).requestFocus(_focusNode);
print('tapped');
},
);
}
}
您需要做的是在构建内部更改焦点,您正试图在屏幕完成重建该小部件之前更改焦点。请尝试使用您自己的代码。
我不确定您是否需要真正聆听焦点变化,或者您是否只想在启用小部件后完成焦点变化,如果您确实想要聆听焦点变化,请告诉我。
class MyCustomForm extends StatefulWidget {
@override
_MyCustomFormState createState() => _MyCustomFormState();
}
class _MyCustomFormState extends State<MyCustomForm> {
FocusNode myFocusNode = FocusNode();
bool _editingField2 = false;
@override
void dispose() {
myFocusNode?.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
//here you do the focus request
if (_editingField2) {
FocusScope.of(context).requestFocus(myFocusNode);
}
return Scaffold(
appBar: AppBar(
title: Text('Text Field Focus'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// The first text field is focused on as soon as the app starts.
TextField(
autofocus: true,
),
// The second text field is created when _editingField2 (after FAB press).
_editingField2
? TextField(
focusNode: myFocusNode,
)
: Text('ayy'),
],
),
),
floatingActionButton: FloatingActionButton(
// Give focus node focus on FAB press.
onPressed: () {
setState(() {
_editingField2 = true;
});
},
tooltip: 'Focus Second Text Field',
child: Icon(Icons.edit),
),
);
}
}