当一个文本输入框被选中并接受输入时,它就被称为获得了“焦点”。通常,用户通过点击来将焦点转移到文本输入框,而开发者则可以使用本指南中描述的工具通过编程方式转移焦点。

管理焦点是创建具有直观流程的表单的基本工具。例如,假设你有一个带有文本输入框的搜索界面。当用户导航到搜索界面时,你可以将焦点设置到搜索词的文本输入框上。这使得用户在屏幕可见时即可开始输入,而无需手动点击文本输入框。

在本指南中,你将学习如何让文本输入框在可见时立即获得焦点,以及如何让文本输入框在按钮被点击时获得焦点。

文本输入框可见时即获得焦点

#

要让文本输入框在可见时立即获得焦点,请使用 autofocus 属性。

dart
TextField(
  autofocus: true,
);

有关处理输入和创建文本输入框的更多信息,请参阅烹饪书的表单部分。

按钮被点击时文本输入框获得焦点

#

除了立即将焦点转移到特定文本输入框之外,你可能还需要在稍后的某个时间点让文本输入框获得焦点。在实际应用中,你可能还需要响应 API 调用或验证错误,让特定的文本输入框获得焦点。在此示例中,我们将在用户按下按钮后通过以下步骤让文本输入框获得焦点

  1. 创建一个 FocusNode
  2. FocusNode 传递给 TextField
  3. 按钮被点击时,让 TextField 获得焦点。

1. 创建一个 FocusNode

#

首先,创建一个 FocusNode。使用 FocusNode 来识别 Flutter “焦点树”中的特定 TextField。这使得你可以在后续步骤中让 TextField 获得焦点。

由于焦点节点是长期存在的对象,请使用 State 对象管理其生命周期。按照以下说明在 State 类的 initState() 方法中创建一个 FocusNode 实例,并在 dispose() 方法中进行清理。

dart
// Define a custom Form widget.
class MyCustomForm extends StatefulWidget {
  const MyCustomForm({super.key});

  @override
  State<MyCustomForm> createState() => _MyCustomFormState();
}

// Define a corresponding State class.
// This class holds data related to the form.
class _MyCustomFormState extends State<MyCustomForm> {
  // Define the focus node. To manage the lifecycle, create the FocusNode in
  // the initState method, and clean it up in the dispose method.
  late FocusNode myFocusNode;

  @override
  void initState() {
    super.initState();

    myFocusNode = FocusNode();
  }

  @override
  void dispose() {
    // Clean up the focus node when the Form is disposed.
    myFocusNode.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // Fill this out in the next step.
  }
}

2. 将 FocusNode 传递给 TextField

#

现在你已经有了一个 FocusNode,将其传递给 build() 方法中的特定 TextField

dart
@override
Widget build(BuildContext context) {
  return TextField(focusNode: myFocusNode);
}

3. 按钮被点击时,让 TextField 获得焦点

#

最后,当用户点击浮动操作按钮时,让文本输入框获得焦点。使用 requestFocus() 方法来执行此任务。

dart
FloatingActionButton(
  // When the button is pressed,
  // give focus to the text field using myFocusNode.
  onPressed: () => myFocusNode.requestFocus(),
),

互动示例

#
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(title: 'Text Field Focus', home: MyCustomForm());
  }
}

// Define a custom Form widget.
class MyCustomForm extends StatefulWidget {
  const MyCustomForm({super.key});

  @override
  State<MyCustomForm> createState() => _MyCustomFormState();
}

// Define a corresponding State class.
// This class holds data related to the form.
class _MyCustomFormState extends State<MyCustomForm> {
  // Define the focus node. To manage the lifecycle, create the FocusNode in
  // the initState method, and clean it up in the dispose method.
  late FocusNode myFocusNode;

  @override
  void initState() {
    super.initState();

    myFocusNode = FocusNode();
  }

  @override
  void dispose() {
    // Clean up the focus node when the Form is disposed.
    myFocusNode.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Text Field Focus')),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            // The first text field is focused on as soon as the app starts.
            const TextField(autofocus: true),
            // The second text field is focused on when a user taps the
            // FloatingActionButton.
            TextField(focusNode: myFocusNode),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        // When the button is pressed,
        // give focus to the text field using myFocusNode.
        onPressed: () => myFocusNode.requestFocus(),
        tooltip: 'Focus Second Text Field',
        child: const Icon(Icons.edit),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}