Repository: flutter
Issue: nested `FormField`'s produce inconsistent state when propagating via `onSave`
Labels: a: tests,a: text input,framework,P2,team-design,triaged-design

### Steps to reproduce

1. run the attached test. 


### Expected results

When the user changes the `Primary:`  TextField and taps on save the `SubFormField.state` changes to reflect the new location.

Inherently i expect that a custom implementation of FormField behaves like a TextFormField

### Actual results

The state doesnt change. See the test group `FormField<Location>`.


### Code sample

<details open><summary>Code sample</summary>

```dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets('change field_1', (WidgetTester tester) async {
    //Setup
    final form = SubFormField();
    const newValue = 'the new value the field should be set to';

    await tester.pumpWidget(MaterialApp(home: Scaffold(body: form)));

    // Enter some text in the TextFormField inside FormField<Location>
    await tester.enterText(find.byKey(const Key("field_1")), newValue);

    // Submit the form
    await tester.tap(find.text('save'));
    await tester.pump();


    // Verify that the state map is updated accordingly
    expect(form.state['field_1'], equals(newValue));
  });

  group("FormField<Location>", () {

    testWidgets('change location.primary', (WidgetTester tester) async {
      //Setup
      final form = SubFormField();
      const newValue = 'the new value the field should be set to';

      await tester.pumpWidget(MaterialApp(home: Scaffold(body: form)));

      // Enter some text in the TextFormField inside FormField<Location>
      await tester.enterText(find.byKey(const Key("primary")), newValue);

      // Submit the form
      await tester.tap(find.text('save'));
      await tester.pump();


      // Verify that the state map is updated accordingly
      expect(form.state['location'].primary, equals(newValue));
    });

    testWidgets('change location.sub', (WidgetTester tester) async {
      final form = SubFormField();
      const newValue = 'the new value the field should be set to';

      await tester.pumpWidget(MaterialApp(home: Scaffold(body: form)));

      final formField = find.byType(FormField<Location>);

      final subField = find.descendant(
        of: formField,
        matching: find.byType(TextFormField),
      ).at(1);


      // Enter some text in the TextFormField inside FormField<Location>
      await tester.enterText(subField, newValue);

      // Submit the form
      await tester.tap(find.text('save'));
      await tester.pump();


      // Verify that the state map is updated accordingly
      expect(form.state['location'], isNotNull);
      expect(form.state['location'].primary, equals(form.initialLocation.primary));
      expect(form.state['location'].sub, equals(newValue));
    });
  });
}


class Location{
  Location({required this.primary,required this.sub});

  final String primary;
  final String sub;

  Location copyWith({String? primary, String? sub}) => Location(primary: primary ?? this.primary,sub: sub ?? this.sub);

  @override
  toString() => "Location(primary: $primary, sub; $sub)";
}

class SubFormField extends StatelessWidget {
  SubFormField({super.key, Location? initialLocation})
      : state = {},
        initialLocation = initialLocation ??
            Location(primary: "1600 Pennsylvania Avenue NW, Washington, DC 20500, USA", sub: "Oval office");

  final Map<String, dynamic> state;

  final GlobalKey<FormState> _formKey = GlobalKey();
  final Location initialLocation;

  _sendSave() {
    if (_formKey.currentState!.validate()) {
      print("state didnt validate");
    }

    _formKey.currentState!.save();
    print(state);
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          TextFormField(
            key: const Key("field_1"),
            initialValue: "this one changes",
            onSaved: (v) => state["field_1"] = v,
          ),
          FormField<Location>(
            initialValue: initialLocation,
            onSaved: (v) => state["location"] = v,
            builder: (state) {
              if (state.value == null) {
                return const CircularProgressIndicator();
              }

              final location = state.value!;
              return ListTile(
                leading: const Icon(Icons.place),
                title: TextFormField(
                  key: const Key("primary"),
                  initialValue: location.primary,
                  decoration: const InputDecoration(labelText: "Primary:"),
                  validator: (val) => val == "" ? "cannot be empty" : null,
                  onSaved: (value) => state.didChange(location.copyWith(primary: value!)),
                ),
                subtitle: TextFormField(
                  key: const Key("sub"),
                  initialValue: location.sub,
                  decoration: const InputDecoration(labelText: "Sub:"),
                  onSaved: (value) => state.didChange(location.copyWith(sub: value)),
                ),
              );
            },
          ),
          ElevatedButton(onPressed: () => _sendSave(), child: const Text("save"))
        ],
      ),
    );
  }
}
```

</details>


### Screenshots or Video

<details open>
<summary>Screenshots / Video demonstration</summary>

[Upload media here]

</details>


### Logs

<details open><summary>Logs</summary>

```console
[Paste your logs here]
```

</details>


### Flutter Doctor output

<details open><summary>Doctor output</summary>

```console
[!] Flutter (Channel stable, 3.19.0, on macOS 14.3 23D56 darwin-x64, locale
    en-DE)
    • Flutter version 3.19.0 on channel stable at
      /usr/local/Caskroom/flutter/3.10.2/flutter
    ! Warning: `dart` on your path resolves to
      /usr/local/Cellar/dart-sdk/3.2.4/libexec/bin/dart, which is not inside
      your current Flutter SDK checkout at
      /usr/local/Caskroom/flutter/3.10.2/flutter. Consider adding
      /usr/local/Caskroom/flutter/3.10.2/flutter/bin to the front of your path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision bae5e49bc2 (13 days ago), 2024-02-13 17:46:18 -0800
    • Engine revision 04817c99c9
    • Dart version 3.3.0
    • DevTools version 2.31.1
    • If those were intentional, you can disregard the above warnings; however
      it is recommended to use "git" directly to perform update checks and
      upgrades.

[!] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /Users/user/Library/Android/sdk
    • Platform android-33, build-tools 33.0.0
    • Java binary at: /Applications/Android
      Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for
      more details.

[✗] Xcode - develop for iOS and macOS
    ✗ Xcode installation is incomplete; a full installation is necessary for iOS
      and macOS development.
      Download at: https://developer.apple.com/xcode/
      Or install Xcode via the App Store.
      Once installed, run:
        sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
        sudo xcodebuild -runFirstLaunch
    ✗ CocoaPods not installed.
        CocoaPods is used to retrieve the iOS and macOS platform side's plugin
        code that responds to your plugin usage on the Dart side.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
      To install see
      https://guides.cocoapods.org/using/getting-started.html#installation for
      instructions.

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)

[✓] IntelliJ IDEA Ultimate Edition (version 2023.3.4)
    • IntelliJ at /Applications/IntelliJ IDEA.app
    • Flutter plugin version 78.1.1
    • Dart plugin version 233.13763.5

[✓] VS Code (version 1.86.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension can be installed from:
      🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected device (2 available)
    • macOS (desktop) • macos  • darwin-x64     • macOS 14.3 23D56 darwin-x64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 122.0.6261.69

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 3 categories.

```

</details>