焦點和文字框

當一個文字框(輸入框)被選中並接受輸入時,被稱為獲得了『焦點』。通常情況下,使用者能夠透過點選文字框以使其聚焦,開發人員也可以使用本文所描述的方法來讓文字框得到焦點。

管理焦點是一種直觀地建立表單流程的基本方法。例如,假設我們有一個帶有文字框的搜尋頁面。當用戶導向到搜尋頁面時,我們可以聚焦文字框的搜尋項。這將允許使用者在搜尋頁面可見時能夠立即開始輸入,而無需手動點選文字框。

在本文中,我們將學習如何聚焦到文字框上,以及點選按鈕時聚焦文字框。

一旦文字框可見,就將其聚焦

為了在文字框可見時將其聚焦,我們可以使用 autofocus 屬性。

TextField(
  autofocus: true,
);

有關處理輸入和建立文字框的更多訊息,請參閱 實用教程的 Forms 部分

點選按鈕時聚焦文字框

我們也可能需要在之後的某個時間點聚焦特定的文字框,而不是立即聚焦它。在這個例子中,我們將看到在使用者按下按鈕後如何聚焦文字框。在實際開發中,你還可能需要聚焦特定的文字框以回應 api 呼叫或錯誤校驗。

  1. 建立一個 FocusNode

  2. FocusNode 傳遞給 TextField

  3. 透過點選按鈕聚焦 TextField

1. 建立一個 FocusNode

首先,我們需要建立一個 FocusNode。我們將使用 FocusNode 來識別 Flutter 的『focus tree』中的特定的 TextField。這將允許我們能夠在接下來的步驟中聚焦 TextField

由於 focus node 是長壽命物件,我們需要使用 State 類來管理生命週期。為此,需要在 State 類別的 initState 方法中建立 FocusNode 實例,並在 dispose 方法中清除它們。

// 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,我們可以將這個 TextField 傳遞給 build() 方法。

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

3. 透過點選按鈕聚焦 TextField

最後,當用戶點選 floating action button 時,我們將要聚焦文字框!為此我們將要使用 requestFocus() 方法來完成此操作。

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