The input box is also a necessary part of the UI. For example, in common login scenarios, you need to enter a user name and password. Multiple input boxes together form a form. The input field in Flutter is implemented by the TextField Widget and the Form Widget by the Form Widget.

A TextField,

TextField is used for text input, and it provides a number of properties. Let’s take a look at what these properties mean one by one.

  const TextField({
    Key key,
    this.controller,
    this.focusNode,
    this.decoration = const InputDecoration(),
    TextInputType keyboardType,
    this.textInputAction,
    this.textCapitalization = TextCapitalization.none,
    this.style,
    this.strutStyle,
    this.textAlign = TextAlign.start,
    this.textAlignVertical,
    this.textDirection,
    this.readOnly = false.this.showCursor,
    this.autofocus = false.this.obscureText = false.this.autocorrect = true.this.maxLines = 1.this.minLines,
    this.expands = false.this.maxLength,
    this.maxLengthEnforced = true.this.onChanged,
    this.onEditingComplete,
    this.onSubmitted,
    this.inputFormatters,
    this.enabled,
    this.cursorWidth = 2.0.this.cursorRadius,
    this.cursorColor,
    this.keyboardAppearance,
    this.scrollPadding = const EdgeInsets.all(20.0),
    this.dragStartBehavior = DragStartBehavior.start,
    this.enableInteractiveSelection,
    this.onTap,
    this.buildCounter,
    this.scrollController,
    this.scrollPhysics,
  })
Copy the code

Controller —- controls the text being edited, which is of type TextEditingController.

FocusNode —- defines the keyboard focus for this Widget.

Decoration —- displays decorations around the TextField. By default, a horizontal line is drawn under the text field, but can be configured to display ICONS, labels, prompt text, and error text.

KeyboardType —- TextInputType Enumeration class that sets the default keyboard input type for this input box. On Android, behavior may vary by device and keyboard provider.

Enumerated values meaning
text Text input keyboard
multiline Multi-line text, used with maxLines (set to null or greater than 1)
number A numeric keypad will pop up
phone The optimized phone number input keyboard will pop up numeric keypad and display “* #”
datetime Optimized date input keyboard, Android will display “: -“
emailAddress The optimized email address will display “@.”
url The optimized URL input keyboard displays “/.”

TextInputAction —- The type of action button used for the keyboard.

enum TextInputAction {
  /// The current input source (for example, [TextField]) has no related input operation.
  none,
  /// Let the operating system determine the most appropriate action.
  unspecified,
  /// Logical meaning: The user completes the action of providing input to a set of inputs, such as a form. It's time for some sort of termination.
  done,
  /// Logical meaning: The user enters some text that represents the destination, such as the name of a restaurant.
  /// The "Go" button is designed to take the user to the part of the application that corresponds to that destination.
  go,
  /// Execute a search query.
  search,
  /// Logical meaning: To send user-written content, such as email or SMS.
  send,
  /// Logical meaning: The user has finished the operation of the current input source and wants to move to the next input source.
  next,
  /// Logical meaning: The user wants to return to the last input source in the group, for example, a form with multiple [TextFields].
  previous,
  /// In iOS apps, the "Back" button and "Continue" button are usually displayed at the top of the screen.
  continueAction,
  /// The user wants to add something, such as a wireless network.
  join,
  /// The user wants route selection, for example, driving route.
  route,
  /// Logical meaning: Initiates a call to the emergency service.
  emergencyCall,
  /// Inserts a newline character, such as [TextField], into the focus text input.
  newline,
}
Copy the code

Texttext3% —- Configures platform keyboards to choose between upper and lower case keyboards.

enum TextCapitalization {
  /// The first letter of each word defaults to uppercase keyboard.
  words,
  /// The first letter of each sentence defaults to uppercase keyboard.
  sentences,
  /// Each character defaults to uppercase on the keyboard.
  characters,
  /// The default is lowercase keyboard.
  none,
}
Copy the code

Style —- TextStyle type, as detailed earlier in the Text Widget section.

StrutStyle —- The strutStyle type, as detailed earlier in the Text Widget section.

TextAlign —- how to align text horizontally.

enum TextAlign {
  /// Align the text on the left edge of the container.
  left,
  /// Align the text on the right edge of the container.
  right,
  /// Align the text in the center of the container.
  center,
  /// An extended line of text that ends with a soft newline filling the container width.
  /// Lines ending with a newline are aligned with the start edge.
  justify,
  /// Align the text at the front of the container.
  start,
  /// Align the text at the end of the container.
  end,
}
Copy the code

TextAlignVertical —- Enter the vertical alignment of the Chinese text.

/// Aligns TextField's input Text with the highest position in the TextField.
static const TextAlignVertical top = TextAlignVertical(y: 1.0);
/// Aligns TextField's input Text to the center of the TextField.
static const TextAlignVertical center = TextAlignVertical(y: 0.0);
/// Aligns TextField's input Text with the bottommost position in TextField.
static const TextAlignVertical bottom = TextAlignVertical(y: 1.0);
Copy the code

TextDirection —- the direction of text, whether it is left to right or right to left (for example, In Arabic or Hebrew).

ReadOnly —- whether to readOnly.

ShowCursor —- Specifies whether to display the cursor.

Autofocus —- Whether to automatically obtain the focus.

ObscureText —- Whether to hide text being edited (for example, for passwords).

Autocorrect —- Whether to enable automatic correction.

MaxLines —- Maximum number of lines.

MinLines —- Minimum number of lines.

This Widget’s height will be adjusted to fill its parent —-.

MaxLength —- Maximum number of characters allowed in a text field.

MaxLengthEnforced —- If true prevents the Widget from allowing more than [maxLength] characters. If [maxLength] is set, [maxLengthEnforced] indicates whether the limit is enforced or provides character counters and warnings only when [maxLength] is exceeded.

OnChanged —- A callback function to change the content of the input box.

OnEditingComplete —- called when the user submits editable content (for example, when the user presses the “Finish” button on the keyboard).

OnSubmitted —- is called when the user indicates that they have finished editing the text of the field.

InputFormatters —- Optional input validation and formatting alternatives. When the text input changes, the formatter runs in the order provided.

Enabled —- If false, the text field is “disabled” : it will ignore the click and its [decoration] will be grayed out.

CursorWidth —- cursorWidth.

CursorRadius —- Cursor rounded corners.

CursorColor —- cursorColor.

KeyboardAppearance —- Appearance of the keyboard. This setting is only supported on iOS devices.

ScrollPadding —- Configure the padding around the edge of [Scrollable] when Textfield is scrolled into the view.

When the Widget gets focus and is not fully visible (for example, partially scrolled out of the screen or overlapped by the keyboard), it will try to make itself visible by scrolling around the [Scrollable] (if any). This value controls how far TextField will be from the edge of [Scrollable] after scrolling.

DragStartBehavior —- setting determines when the drag officially begins when the user starts dragging.

EnableInteractiveSelection – if it is true, then long press the TextField will select text and show cut/copy/paste the menu, and click the insert mobile text symbols. If false, most accessibility support for selecting text, copying and pasting, and moving caret is disabled.

OnTap —- is called when the user clicks on this text field.

BuildCounter —- generates callbacks to custom [inputDecorator.counter] widgets. The parameters passed, see [InputCounterWidgetBuilder]. The returned Widget will be placed below the line in place of the default Widget built when [counterText] is specified.

ScrollController —- [scrollController] (the object that can be used to control where this Widget is rolled to) to be used when scrolling vertically. If null, it instantiates a new ScrollController.

ScrollPhysics —- [scrollPhysics] to use when scrolling vertically (how widgets should respond to user input). If not specified, it will run based on the current platform.

TextField has too many fields to control, so let’s start with the simplest input field, just one line of code.

TextField()
Copy the code

1.1 use InputDecoration

The decorations displayed around the TextField. By default, a horizontal line is drawn under the text field, but can be configured to display ICONS, labels, prompt text, and error text. There are a lot of properties, so if you’re interested, you can go through them one by one, and I won’t go into them any more.

  const InputDecoration({
    this.icon,
    this.labelText,
    this.labelStyle,
    this.helperText,
    this.helperStyle,
    this.hintText,
    this.hintStyle,
    this.hintMaxLines,
    this.errorText,
    this.errorStyle,
    this.errorMaxLines,
    this.hasFloatingPlaceholder = true.this.isDense,
    this.contentPadding,
    this.prefixIcon,
    this.prefix,
    this.prefixText,
    this.prefixStyle,
    this.suffixIcon,
    this.suffix,
    this.suffixText,
    this.suffixStyle,
    this.counter,
    this.counterText,
    this.counterStyle,
    this.filled,
    this.fillColor,
    this.focusColor,
    this.hoverColor,
    this.errorBorder,
    this.focusedBorder,
    this.focusedErrorBorder,
    this.disabledBorder,
    this.enabledBorder,
    this.border,
    this.enabled = true.this.semanticCounterText,
    this.alignLabelWithHint,
  }) : assert(enabled ! =null),
Copy the code

The following implementation of a simple login input interface.

class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Home Page"), ), body: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[TextField(autofocus: true, decoration: InputDecoration(labelText: "username ", hintText:" please enter username ", prefixIcon: Icon(Icons. Person)),), TextField(decoration: InputDecoration(labelText: "code ", hintText:" please input password ", prefixIcon: Icon(Icons.lock)), obscureText: true, ), ], )); }}Copy the code

1.2 use textInputAction

We know that textInputAction is used to control the type of action buttons on the keyboard. Take a look at how to affect the appearance of buttons on the keyboard.

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextField(
                autofocus: true,
                decoration: InputDecoration(
                    labelText: "Google it.",
                    hintText: "Please enter what you are looking for.",
                    prefixIcon: Icon(Icons.search)),
                textInputAction: TextInputAction.search),
            TextField(
              decoration: InputDecoration(
                labelText: "Control group"(), () [(). }}Copy the code

1.3 use the controller

As long as the Controller is set, it’s very easy to get the TextField.

class _MyHomePageState extends State<MyHomePage> {
  TextEditingController _searchController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextField(
              autofocus: true,
              decoration: InputDecoration(
                  labelText: "Google it.",
                  hintText: "Please enter what you are looking for.",
                  prefixIcon: Icon(Icons.search)),
              textInputAction: TextInputAction.search,
              controller: _searchController,
            ),
            RaisedButton(
              onPressed: () {
                setState(() {});
              },
              child: Text("Get TextField content"), ), Text(_searchController.text), ], )); }}Copy the code

1.4 use focusNode

Focus can be controlled by FocusNode and FocusScopeNode. By default, focus is managed by FocusScope, which represents the focus control range within which FocusScopeNode can be used to move focus between input boxes, set the default focus, and so on. We can get the default FocusScope.of(context) in the Widget tree.

Three input fields are defined below, and the focus is between them. Click the Focus move button to move the focus from top to bottom.

class _MyHomePageState extends State<MyHomePage> {
  FocusNode focusNode1 = new FocusNode();
  FocusNode focusNode2 = new FocusNode();
  FocusNode focusNode3 = new FocusNode();

  FocusScopeNode focusScopeNode;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Home Page"),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            TextField(
              autofocus: true,
              focusNode: focusNode1,
              decoration: InputDecoration(
                labelText: "Enter 1",
              ),
            ),
            TextField(
              focusNode: focusNode2,
              decoration: InputDecoration(
                labelText: "Type 2",
              ),
            ),
            TextField(
              focusNode: focusNode3,
              decoration: InputDecoration(
                labelText: "Type 3",
              ),
            ),
            RaisedButton(
              onPressed: () {
                setState(() {
                  if (null == focusScopeNode) {
                    focusScopeNode = FocusScope.of(context);
                  }

                  if (focusNode1.hasFocus) {
                    focusScopeNode.requestFocus(focusNode2);
                  } else if (focusNode2.hasFocus) {
                    focusScopeNode.requestFocus(focusNode3);
                  } else if (focusNode3.hasFocus) {
                    focusScopeNode.requestFocus(focusNode1);
                  } else{ focusScopeNode.requestFocus(focusNode1); }}); }, child: Text("Focus shift"),),])); }}Copy the code

Second, the Form

Flutter provides a Form component that groups input fields and performs uniform operations such as input validation, input field resetting, and input saving. This is useful when many fields need to be submitted.

  const Form({
    Key key,
    @required this.child,
    this.autovalidate = false.this.onWillPop,
    this.onChanged,
  })
Copy the code

The [child] parameter cannot be null.

Autovalidate —- Whether to automatically validate input; When true, each subformField is automatically validated and displays an error message when its content changes. Otherwise, you need to check manually by calling formstate.validate ().

OnWillPop —- determines whether the route from the Form can return directly (i.e. by clicking the return button). This callback returns a Future object. If the Future is false, the current route does not return. If true, the last route is returned. This property is typically used to intercept the back button.

This callback is triggered when the contents of any of the FormField children of the onChanged —- Form change.

2.1 FormField

A descendant of Form must be of type FormField, which is an abstract class.

  const FormField({
    Key key,
    @required this.builder,
    this.onSaved,
    this.validator,
    this.initialValue,
    this.autovalidate = false.this.enabled = true,})Copy the code

These properties are essentially self-explanatory.

OnSaved —- Save the callback.

Validator —- Validates the callback.

InitialValue —- initialValue.

Autovalidate —- Specifies whether automatic verification is performed.

Flutter provides a TextFormField Widget that inherits from the FormField class and is also a wrapper class for TextField, so it includes TextField properties in addition to those defined by the FormField.

  TextFormField({
    Key key,
    this.controller,
    String initialValue,
    FocusNode focusNode,
    InputDecoration decoration = const InputDecoration(),
    TextInputType keyboardType,
    TextCapitalization textCapitalization = TextCapitalization.none,
    TextInputAction textInputAction,
    TextStyle style,
    StrutStyle strutStyle,
    TextDirection textDirection,
    TextAlign textAlign = TextAlign.start,
    bool autofocus = false.bool readOnly = false.bool showCursor,
    bool obscureText = false.bool autocorrect = true.bool autovalidate = false.bool maxLengthEnforced = true.int maxLines = 1.int minLines,
    bool expands = false.int maxLength,
    VoidCallback onEditingComplete,
    ValueChanged<String> onFieldSubmitted,
    FormFieldSetter<String> onSaved,
    FormFieldValidator<String> validator,
    List<TextInputFormatter> inputFormatters,
    bool enabled = true.double cursorWidth = 2.0,
    Radius cursorRadius,
    Color cursorColor,
    Brightness keyboardAppearance,
    EdgeInsets scrollPadding = const EdgeInsets.all(20.0),
    bool enableInteractiveSelection = true,
    InputCounterWidgetBuilder buildCounter,
  })
Copy the code

2.2 FormState

FormState is the state class associated with the [Form] Widget. The [FormState] object can be used for [save], [reset], and [validate] for each [FormField] descendant of the association [Form].

Formstate.validate () : This method calls the validate callback of the descendant FormField, which returns false if any validations fail, and all validations return an error message.

Formstate.save () : After calling this method, the save callback of the Form descendant FormField is called to save the Form content.

Formstate.reset () : This method clears the descendant FormField.

Here is an example.

class FormTestRoute extends StatefulWidget {
  @override
  _FormTestRouteState createState() => new _FormTestRouteState();
}

class _FormTestRouteState extends State<FormTestRoute> {
  TextEditingController _nameController = new TextEditingController();
  TextEditingController _pwdController = new TextEditingController();
  GlobalKey _formKey = new GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Form Test"),
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 8.0),
        child: Form(
          key: _formKey,
          autovalidate: true,
          child: Column(
            children: <Widget>[
              TextFormField(
                  autofocus: true,
                  controller: _nameController,
                  decoration: InputDecoration(
                      labelText: "Username",
                      hintText: "Please enter user name",
                      icon: Icon(Icons.person)),
                  validator: (v) {
                    return v.trim().length > 0 ? null : "User name cannot be empty";
                  }),
              TextFormField(
                  controller: _pwdController,
                  decoration: InputDecoration(
                      labelText: "Secret code",
                      hintText: "Please enter your password",
                      icon: Icon(Icons.lock)),
                  obscureText: true,
                  validator: (v) {
                    return v.trim().length > 5 ? null : "Password must be no less than six characters.";
                  }),
              // Login button
              Padding(
                padding: const EdgeInsets.only(top: 10.0),
                child: Row(
                  children: <Widget>[
                    Expanded(
                      child: RaisedButton(
                        padding: EdgeInsets.all(6.0),
                        child: Text("Login"),
                        color: Theme.of(context).primaryColor,
                        textColor: Colors.white,
                        onPressed: () {
                          if ((_formKey.currentState as FormState).validate()) {
                            // Verify that data is submitted
                            setState(() {});
                          }
                        },
                      ),
                    ),
                  ],
                ),
              ),
              Text("My username =${_nameController.text}, the password =${_pwdController.text}"),],),),),); }}Copy the code