1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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
157
// 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].
///
/// This is a convenience widget that wraps a [TextField] widget in a
/// [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.
///
/// 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.
///
/// For a documentation about the various parameters, see [TextField].
///
/// 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> {
/// Creates a [FormField] that contains a [TextField].
///
/// 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.
///
/// For documentation about the various parameters, see the [TextField] class
/// and [new TextField], the constructor.
TextFormField({
Key key,
this.controller,
String initialValue: '',
FocusNode focusNode,
InputDecoration decoration: const InputDecoration(),
TextInputType keyboardType: TextInputType.text,
TextStyle style,
bool autofocus: false,
bool obscureText: false,
bool autocorrect: true,
int maxLines: 1,
FormFieldSetter<String> onSaved,
FormFieldValidator<String> validator,
List<TextInputFormatter> inputFormatters,
}) : assert(initialValue != null),
assert(keyboardType != null),
assert(autofocus != null),
assert(obscureText != null),
assert(autocorrect != null),
assert(maxLines == null || maxLines > 0),
super(
key: key,
initialValue: initialValue,
onSaved: onSaved,
validator: validator,
builder: (FormFieldState<String> field) {
final _TextFormFieldState state = field;
return new TextField(
controller: state._effectiveController,
focusNode: focusNode,
decoration: decoration.copyWith(errorText: field.errorText),
keyboardType: keyboardType,
style: style,
autofocus: autofocus,
obscureText: obscureText,
autocorrect: autocorrect,
maxLines: maxLines,
onChanged: field.onChanged,
inputFormatters: inputFormatters,
);
},
);
/// 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);
}
}