text_form_field.dart 5.22 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';

import 'input_decorator.dart';
import 'text_field.dart';

/// A [FormField] that contains a [TextField].
///
13
/// This is a convenience widget that wraps a [TextField] widget in a
14 15 16 17 18 19 20
/// [FormField].
///
/// A [Form] ancestor is not required. The [Form] simply makes it easier to
/// save, reset, or validate multiple fields at once. To use without a [Form],
/// pass a [GlobalKey] to the constructor and use [GlobalKey.currentState] to
/// save or reset the form field.
///
21 22 23 24
/// When a [controller] is specified, it can be used to control the text being
/// edited. Its content will be overwritten by [initialValue] (which defaults
/// to the empty string) on creation and when [reset] is called.
///
25 26
/// For a documentation about the various parameters, see [TextField].
///
27 28 29 30 31 32 33 34
/// See also:
///
///  * <https://material.google.com/components/text-fields.html>
///  * [TextField], which is the underlying text field without the [Form]
///    integration.
///  * [InputDecorator], which shows the labels and other visual elements that
///    surround the actual text editing widget.
class TextFormField extends FormField<String> {
35 36
  /// Creates a [FormField] that contains a [TextField].
  ///
37 38 39 40
  /// When a [controller] is specified, it can be used to control the text
  /// being edited. Its content will be overwritten by [initialValue] (which
  /// defaults to the empty string) on creation and when [reset] is called.
  ///
41 42
  /// For documentation about the various parameters, see the [TextField] class
  /// and [new TextField], the constructor.
43 44
  TextFormField({
    Key key,
45 46
    this.controller,
    String initialValue: '',
47 48 49 50 51 52
    FocusNode focusNode,
    InputDecoration decoration: const InputDecoration(),
    TextInputType keyboardType: TextInputType.text,
    TextStyle style,
    bool autofocus: false,
    bool obscureText: false,
53
    bool autocorrect: true,
54 55 56
    int maxLines: 1,
    FormFieldSetter<String> onSaved,
    FormFieldValidator<String> validator,
57
    List<TextInputFormatter> inputFormatters,
58 59
  }) : assert(initialValue != null),
       assert(keyboardType != null),
60 61
       assert(autofocus != null),
       assert(obscureText != null),
62
       assert(autocorrect != null),
63 64
       assert(maxLines == null || maxLines > 0),
       super(
65
    key: key,
66
    initialValue: initialValue,
67 68 69
    onSaved: onSaved,
    validator: validator,
    builder: (FormFieldState<String> field) {
70
      final _TextFormFieldState state = field;
71
      return new TextField(
72
        controller: state._effectiveController,
73 74 75 76 77 78
        focusNode: focusNode,
        decoration: decoration.copyWith(errorText: field.errorText),
        keyboardType: keyboardType,
        style: style,
        autofocus: autofocus,
        obscureText: obscureText,
79
        autocorrect: autocorrect,
80
        maxLines: maxLines,
81
        onChanged: field.onChanged,
82
        inputFormatters: inputFormatters,
83 84 85
      );
    },
  );
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156

  /// Controls the text being edited.
  ///
  /// If null, this widget will create its own [TextEditingController].
  final TextEditingController controller;

  @override
  _TextFormFieldState createState() => new _TextFormFieldState();
}

class _TextFormFieldState extends FormFieldState<String> {
  TextEditingController _controller;

  TextEditingController get _effectiveController => widget.controller ?? _controller;

  @override
  TextFormField get widget => super.widget;

  @override
  void initState() {
    super.initState();
    if (widget.controller == null) {
      _controller = new TextEditingController(text: widget.initialValue);
    } else {
      widget.controller.text = widget.initialValue;
      widget.controller.addListener(_handleControllerChanged);
    }
  }

  @override
  void didUpdateWidget(TextFormField oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.controller != oldWidget.controller) {
      oldWidget.controller?.removeListener(_handleControllerChanged);
      widget.controller?.addListener(_handleControllerChanged);

      if (oldWidget.controller != null && widget.controller == null)
        _controller = new TextEditingController.fromValue(oldWidget.controller.value);
      if (widget.controller != null) {
        setValue(widget.controller.text);
        if (oldWidget.controller == null)
          _controller = null;
      }
    }
  }

  @override
  void dispose() {
    widget.controller?.removeListener(_handleControllerChanged);
    super.dispose();
  }

  @override
  void reset() {
    super.reset();
    setState(() {
      _effectiveController.text = widget.initialValue;
    });
  }

  void _handleControllerChanged() {
    // Suppress changes that originated from within this class.
    //
    // In the case where a controller has been passed in to this widget, we
    // register this change listener. In these cases, we'll also receive change
    // notifications for changes originating from within this class -- for
    // example, the reset() method. In such cases, the FormField value will
    // already have been set.
    if (_effectiveController.text != value)
      onChanged(_effectiveController.text);
  }
157
}