0Pricing
Flutter Mobile Development · 课时

表单组件与控制器

了解如何使用 `Form` 组件管理多个文本字段,并使用 `TextEditingController` 控制用户输入。

表单组件与控制器 是 CoddyKit 上的免费 Flutter Mobile Development 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Flutter Mobile Development 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Flutter Mobile Development 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

Forms: User Input Essentials

Forms are fundamental for almost any interactive mobile application. They allow users to input data, whether it's for logging in, signing up, updating profiles, or submitting information.

In Flutter, forms are built using a combination of widgets designed to handle user input efficiently and robustly.

Organizing Inputs with Form

The Form widget acts as a container for grouping multiple input fields. It provides a way to manage the state of these fields, validate them, and save their values all at once.

Think of it as the parent that oversees all its input children. Here's how to start a basic form structure:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('My Form App')),
        body: Center(
          child: Form(
            child: Column(
              children: [
                // Form fields will go here
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Your First Input: TextFormField

While you can use TextField for input, TextFormField is specifically designed to work seamlessly within a Form widget. It offers built-in features for validation, saving, and error display.

Let's add a simple TextFormField to our form:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('My Form App')),
        body: Center(
          child: Form(
            child: Column(
              children: const [
                Padding(
                  padding: EdgeInsets.all(16.0),
                  child: TextFormField(
                    decoration: InputDecoration(
                      labelText: 'Enter your name',
                      border: OutlineInputBorder(),
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Controlling Input: TextEditingController

To programmatically read, set, or modify the text in a TextFormField (or TextField), you use a TextEditingController. It acts as a communication bridge between your code and the text input widget.

It's crucial to dispose of controllers when they're no longer needed to prevent memory leaks, typically in the dispose() method of a StatefulWidget.

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final TextEditingController _myController = TextEditingController();

  @override
  void dispose() {
    _myController.dispose(); // Important: dispose the controller!
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Controller Demo')),
        body: Center(
          child: Padding(
            padding: const EdgeInsets.all(16.0),
            child: TextField( // Using TextField for clarity
              controller: _myController,
              decoration: const InputDecoration(
                labelText: 'Type something',
                border: OutlineInputBorder(),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Linking Controller & TextFormField

Now, let's connect our TextEditingController to a TextFormField. This allows us to access the text entered by the user directly from the controller, for example, when a button is pressed.

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final TextEditingController _nameController = TextEditingController();

  @override
  void dispose() {
    _nameController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Controller Link')),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            children: [
              TextFormField(
                controller: _nameController,
                decoration: const InputDecoration(
                  labelText: 'Your Name',
                  border: OutlineInputBorder(),
                ),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: () {
                  print('Name: ${_nameController.text}');
                },
                child: const Text('Get Name'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Managing Form State with GlobalKey

To interact with the Form widget itself – for example, to validate all its fields or save their state – you need a way to reference it. This is done using a GlobalKey<FormState>.

The GlobalKey provides access to the Form's internal state, allowing you to trigger actions like validate() or save() on all its children.

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _formKey = GlobalKey<FormState>(); // Declare the GlobalKey

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('GlobalKey Demo')),
        body: Form(
          key: _formKey, // Assign the GlobalKey to the Form
          child: Column(
            children: const [
              Padding(
                padding: EdgeInsets.all(16.0),
                child: TextFormField(
                  decoration: InputDecoration(
                    labelText: 'Email',
                    border: OutlineInputBorder(),
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Submitting Your Form

Combining Form, GlobalKey, and TextEditingControllers allows you to build a functional form. When a submit button is pressed, you can use the _formKey to access the form's state and process the input.

Here's a login form example where we print the collected data upon submission.

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _formKey = GlobalKey<FormState>();
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  @override
  void dispose() {
    _usernameController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  void _submitForm() {
    // In a real app, you'd add validation here (covered in next lesson)
    print('Username: ${_usernameController.text}');
    print('Password: ${_passwordController.text}');
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('Processing Login Data')),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Login Form')),
        body: Form(
          key: _formKey,
          child: Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              children: [
                TextFormField(
                  controller: _usernameController,
                  decoration: const InputDecoration(labelText: 'Username'),
                ),
                TextFormField(
                  controller: _passwordController,
                  obscureText: true,
                  decoration: const InputDecoration(labelText: 'Password'),
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(vertical: 16.0),
                  child: ElevatedButton(
                    onPressed: _submitForm,
                    child: const Text('Submit'),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Retrieving All Form Inputs

When you have multiple TextFormField widgets in your form, each linked to its own TextEditingController, retrieving all user inputs is straightforward. You simply access the .text property of each controller.

This makes it easy to collect all necessary data when the user is ready to submit their information.

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _phoneController = TextEditingController();

  @override
  void dispose() {
    _emailController.dispose();
    _phoneController.dispose();
    super.dispose();
  }

  void _getData() {
    print('Email: ${_emailController.text}');
    print('Phone: ${_phoneController.text}');
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Email: ${_emailController.text}, Phone: ${_phoneController.text}')),
    );
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Multi-Input Get')),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            children: [
              TextFormField(
                controller: _emailController,
                decoration: const InputDecoration(labelText: 'Email'),
                keyboardType: TextInputType.emailAddress,
              ),
              const SizedBox(height: 10),
              TextFormField(
                controller: _phoneController,
                decoration: const InputDecoration(labelText: 'Phone'),
                keyboardType: TextInputType.phone,
              ),
              const SizedBox(height: 20),
              ElevatedButton(
                onPressed: _getData,
                child: const Text('Show Data'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Resetting Input Fields

After a form submission, or if you want to provide a 'Clear' button, you can easily reset the text in a TextFormField. Simply call the .clear() method on its associated TextEditingController, or set its .text property to an empty string.

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final TextEditingController _inputController = TextEditingController();

  @override
  void dispose() {
    _inputController.dispose();
    super.dispose();
  }

  void _clearInput() {
    _inputController.clear(); // Clears the text in the TextFormField
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Clear Input Demo')),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            children: [
              TextFormField(
                controller: _inputController,
                decoration: const InputDecoration(
                  labelText: 'Type here',
                  border: OutlineInputBorder(),
                ),
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                onPressed: _clearInput,
                child: const Text('Clear Text'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Form & Controller Check

Test your understanding of Flutter forms and controllers.

Recap: Forms & Controllers

In this lesson, we explored the foundational elements for building user input forms in Flutter:

  • The Form widget acts as a parent container for managing multiple input fields.
  • TextFormField is the specialized widget for text input within a Form, offering built-in form integration.
  • The TextEditingController allows you to programmatically control, read, and modify the text in an input field.
  • A GlobalKey<FormState> is used to access the Form's state, enabling actions like validation or saving.
  • Remember to dispose of your TextEditingControllers to prevent memory leaks!

Next, we'll dive deeper into input validation techniques to ensure your forms collect correct and useful data!

常见问题解答

「表单组件与控制器」课时是免费的吗?

是的 — 「表单组件与控制器」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Flutter Mobile Development 课程的其余内容,请升级到 CoddyKit PRO。 Flutter Mobile Development 课程共包含 4 节课。

「表单组件与控制器」这节课中我会学到什么?

了解如何使用 `Form` 组件管理多个文本字段,并使用 `TextEditingController` 控制用户输入。 你通过在浏览器中直接运行的动手代码来练习 Flutter Mobile Development,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Flutter Mobile Development 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Flutter Mobile Development 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「表单组件与控制器」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Flutter Mobile Development 课中编写并运行代码吗?

能。每节 Flutter Mobile Development 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 表单组件与控制器
  2. 输入验证技术
  3. 自定义表单字段
  4. 焦点、键盘与输入体验
← 返回 Flutter Mobile Development