Text form field initial value (#15484)

diff --git a/packages/flutter/lib/src/material/text_form_field.dart b/packages/flutter/lib/src/material/text_form_field.dart
index 38f5690..fea3d66 100644
--- a/packages/flutter/lib/src/material/text_form_field.dart
+++ b/packages/flutter/lib/src/material/text_form_field.dart
@@ -19,9 +19,15 @@
 /// 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.
+/// When a [controller] is specified, its [TextEditingController.text]
+/// defines the [initialValue]. If this [FormField] is part of a scrolling
+/// container that lazily constructs its children, like a [ListView] or a
+/// [CustomScrollView], then a [controller] should be specified.
+/// The controller's lifetime should be managed by a stateful widget ancestor
+/// of the scrolling container.
+///
+/// If a [controller] is not specified, [initialValue] can be used to give
+/// the automatically generated controller an initial value.
 ///
 /// For a documentation about the various parameters, see [TextField].
 ///
@@ -35,16 +41,17 @@
 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.
+  /// When a [controller] is specified, [initialValue] must be null (the
+  /// default). If [controller] is null, then a [TextEditingController]
+  /// will be constructed automatically and its `text` will be initialized
+  /// to [initalValue] or the empty string.
   ///
   /// For documentation about the various parameters, see the [TextField] class
   /// and [new TextField], the constructor.
   TextFormField({
     Key key,
     this.controller,
-    String initialValue: '',
+    String initialValue,
     FocusNode focusNode,
     InputDecoration decoration: const InputDecoration(),
     TextInputType keyboardType: TextInputType.text,
@@ -58,7 +65,7 @@
     FormFieldSetter<String> onSaved,
     FormFieldValidator<String> validator,
     List<TextInputFormatter> inputFormatters,
-  }) : assert(initialValue != null),
+  }) : assert(initialValue == null || controller == null),
        assert(keyboardType != null),
        assert(textAlign != null),
        assert(autofocus != null),
@@ -67,7 +74,7 @@
        assert(maxLines == null || maxLines > 0),
        super(
     key: key,
-    initialValue: initialValue,
+    initialValue: controller != null ? controller.text : (initialValue ?? ''),
     onSaved: onSaved,
     validator: validator,
     builder: (FormFieldState<String> field) {
@@ -94,7 +101,8 @@
 
   /// Controls the text being edited.
   ///
-  /// If null, this widget will create its own [TextEditingController].
+  /// If null, this widget will create its own [TextEditingController] and
+  /// initialize its [TextEditingController.text] with [initialValue].
   final TextEditingController controller;
 
   @override
@@ -115,7 +123,6 @@
     if (widget.controller == null) {
       _controller = new TextEditingController(text: widget.initialValue);
     } else {
-      widget.controller.text = widget.initialValue;
       widget.controller.addListener(_handleControllerChanged);
     }
   }
diff --git a/packages/flutter/test/widgets/form_test.dart b/packages/flutter/test/widgets/form_test.dart
index 44e81af..4756b5c 100644
--- a/packages/flutter/test/widgets/form_test.dart
+++ b/packages/flutter/test/widgets/form_test.dart
@@ -204,8 +204,8 @@
     expect(editableText.widget.controller.text, equals('world'));
   });
 
-  testWidgets('Provide initial value to input when controller is specified', (WidgetTester tester) async {
-    final TextEditingController controller = new TextEditingController();
+  testWidgets('Controller defines initial value', (WidgetTester tester) async {
+    final TextEditingController controller = new TextEditingController(text: 'hello');
     const String initialValue = 'hello';
     final GlobalKey<FormFieldState<String>> inputKey = new GlobalKey<FormFieldState<String>>();
 
@@ -217,7 +217,6 @@
             child: new Form(
               child: new TextFormField(
                 key: inputKey,
-                initialValue: 'hello',
                 controller: controller,
               ),
             ),
@@ -251,7 +250,6 @@
     final GlobalKey<FormState> formKey = new GlobalKey<FormState>();
     final GlobalKey<FormFieldState<String>> inputKey = new GlobalKey<FormFieldState<String>>();
     final TextEditingController controller = new TextEditingController(text: 'Plover');
-    const String initialValue = 'Plugh';
 
     Widget builder() {
       return new Directionality(
@@ -263,7 +261,7 @@
               child: new TextFormField(
                 key: inputKey,
                 controller: controller,
-                initialValue: initialValue,
+                // initialValue is 'Plover'
               ),
             ),
           ),
@@ -284,9 +282,9 @@
     // verify value resets to initialValue on reset.
     formKey.currentState.reset();
     await tester.idle();
-    expect(inputKey.currentState.value, equals(initialValue));
-    expect(editableText.widget.controller.text, equals(initialValue));
-    expect(controller.text, equals(initialValue));
+    expect(inputKey.currentState.value, equals('Plover'));
+    expect(editableText.widget.controller.text, equals('Plover'));
+    expect(controller.text, equals('Plover'));
   });
 
   testWidgets('TextEditingController updates to/from form field value', (WidgetTester tester) async {