如何正确聚焦基于焦点节点的hasFocus值有条件创建的Textfield?

时间:2019-11-16 00:20:08

标签: flutter focus textfield listviewitem

使用我当前的代码,TextField成为焦点,但是没有触发光标和键盘(需要再次点击)。我相信这是因为当焦点最初聚焦时,TextField不存在,但是我一直在努力寻找解决方案。

以下是根据菜谱食谱对问题的简单再现:

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');
      },
    );
  }
}

1 个答案:

答案 0 :(得分:0)

您需要做的是在构建中更改焦点,您要在屏幕完成重建该窗口小部件之前尝试更改焦点。请使用您自己的代码尝试这个。

我不确定您是否真的需要收听焦点更改,还是只想在启用小部件后完成焦点更改,如果您确实想收听焦点更改,请告诉我。

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),
      ),
    );
  }
}