Flutter:多个小部件使用相同的 GlobalKey 或重复的 GlobalKey

2024-02-06

我正在尝试创建一个动态表单并使用 TextFormField 进行验证。

下面是给出错误的代码多个小部件使用相同的 GlobalKey 或 Duplicate Global key。 我不确定如何解决这个问题,或者如何使动态表单按照标准变得干净。

import 'package:flutter/material.dart';

class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
  
}

class _AppState extends State<App> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  String person;
  String age;
  String job;

  var nameTECs = <TextEditingController>[];
  var ageTECs = <TextEditingController>[];
  var jobTECs = <TextEditingController>[];
  var cards = <Card>[];

      var nameController = TextEditingController();
    var ageController = TextEditingController();
    var jobController = TextEditingController();

  @override
  void initState() {
    super.initState();
    cards.add(createCard());
  }


   Card createCard() {
     nameTECs.add(nameController);
    ageTECs.add(ageController);
    jobTECs.add(jobController);
    return Card(
      child:new Form(
        key: _formKey,
        child: Column(
         mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Text('Person ${cards.length + 1}'),
          TextFormField(
            style: TextStyle(color: Colors.blue),
              controller: nameController,
              decoration: InputDecoration(labelText: 'Full Name'),
              validator: validatetext,
                            onSaved: (String val) {
                              person = val;
                          },
              ),
              
          TextFormField(
            style: TextStyle(color: Colors.blue),
              controller: ageController,
              decoration: InputDecoration(labelText: 'Age'),
              validator: validatetext,
                            onSaved: (String val) {
                              age = val;
                          },
              ),
          TextFormField(
            style: TextStyle(color: Colors.blue),
              controller: jobController,
              decoration: InputDecoration(labelText: 'Study/ job'),
              validator: validatetext,
                            onSaved: (String val) {
                              job = val;
                          },
            ),
        ],
      ),
      ),
    );
  }

  

  void _validateInputs() {
   print('button');      
      if (_formKey.currentState.validate()) {
    //    If all data are correct then save data to out variables
        _formKey.currentState.save();
        _onDone();
        }
     }

  _onDone() {
    List<PersonEntry> entries = [];
    for (int i = 0; i < cards.length; i++) {
      var name = nameTECs[i].text;
      var age = ageTECs[i].text;
      var job = jobTECs[i].text;
      entries.add(PersonEntry(name, age, job));
    }
    Navigator.pop(context, entries);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: <Widget>[
          Expanded(
            child: ListView.builder(
              itemCount: cards.length,
              itemBuilder: (BuildContext context, int index) {
                return cards[index];
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: RaisedButton(
              child: Text('Add new'),
              onPressed: () => setState(() => cards.add(createCard())),
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: RaisedButton(
              child: Text('Remove last'),
              onPressed: () => setState(() => cards.removeLast()),
            ),
          )

        ],
      ),
      floatingActionButton:
          FloatingActionButton(child: Icon(Icons.save), onPressed: _validateInputs),
    );
  }
}

class PersonEntry {
  final String name;
  final String age;
  final String studyJob;

  PersonEntry(this.name, this.age, this.studyJob);
  @override
  String toString() {
    return 'Person: name= $name, age= $age, study job= $studyJob';
  }
}

String validatetext(String value) {
    if (value.length < 5)
      return 'More than 5 char is required';
    else
      return null;
  }

万一有人想要完全错误。

The following assertion was thrown while finalizing the widget tree:
Multiple widgets used the same GlobalKey.

The key [LabeledGlobalKey<FormState>#89788] was used by multiple widgets. The parents of those widgets were:
- Semantics(container: false, properties: SemanticsProperties, label: null, value: null, hint: null, hintOverrides: null, renderObject: RenderSemanticsAnnotations#65de2 relayoutBoundary=up10)
- Semantics(container: false, properties: SemanticsProperties, label: null, value: null, hint: null, hintOverrides: null, renderObject: RenderSemanticsAnnotations#f4085 relayoutBoundary=up10)
A GlobalKey can only be specified on one widget at a time in the widget tree.
When the exception was thrown, this was the stack
#0      GlobalKey._debugVerifyGlobalKeyReservation.<anonymous closure>.<anonymous closure>.<anonymous closure> 
package:flutter/…/widgets/framework.dart:246
#1      _LinkedHashMapMixin.forEach  (dart:collection-patch/compact_hash.dart:379:8)
#2      GlobalKey._debugVerifyGlobalKeyReservation.<anonymous closure>.<anonymous closure> 
package:flutter/…/widgets/framework.dart:193
#3      _LinkedHashMapMixin.forEach  (dart:collection-patch/compact_hash.dart:379:8)
#4      GlobalKey._debugVerifyGlobalKeyReservation.<anonymous closure> 

问题是您使用相同的密钥_formKey当你所有的forms。您可以创建一个List of _formKeys其中包含Globalkey<FormState>并根据卡片的长度添加或删除密钥。

我使用您的代码添加了一个演示作为示例:

class App extends StatefulWidget {
  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {
  List<GlobalKey<FormState>> _formKeys = [
    GlobalKey<FormState>()
  ]; // create a list of form keys

  String person;
  String age;
  String job;

  var nameTECs = <TextEditingController>[];
  var ageTECs = <TextEditingController>[];
  var jobTECs = <TextEditingController>[];
  var cards = <Card>[];

  var nameController = TextEditingController();
  var ageController = TextEditingController();
  var jobController = TextEditingController();

  @override
  void initState() {
    super.initState();
    cards.add(createCard());
  }

  Card createCard() {
    nameTECs.add(nameController);
    ageTECs.add(ageController);
    jobTECs.add(jobController);
    return Card(
      child: new Form(
        key: _formKeys[_formKeys.length-1], // acess each form key here
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            Text('Person ${cards.length + 1}'),
            TextFormField(
              style: TextStyle(color: Colors.blue),
              controller: nameController,
              decoration: InputDecoration(labelText: 'Full Name'),
              validator: validatetext,
              onSaved: (String val) {
                person = val;
              },
            ),
            TextFormField(
              style: TextStyle(color: Colors.blue),
              controller: ageController,
              decoration: InputDecoration(labelText: 'Age'),
              validator: validatetext,
              onSaved: (String val) {
                age = val;
              },
            ),
            TextFormField(
              style: TextStyle(color: Colors.blue),
              controller: jobController,
              decoration: InputDecoration(labelText: 'Study/ job'),
              validator: validatetext,
              onSaved: (String val) {
                job = val;
              },
            ),
          ],
        ),
      ),
    );
  }

  void _validateInputs() {
    print('button');
    for (int i = 0; i < _formKeys.length; i++) { // validate the form keys here
      if (_formKeys[i].currentState.validate()) {
        // validate each form
        //    If all data are correct then save data to out variables
        _formKeys[i].currentState.save(); // dave each form
        _onDone();
      }
    }
  }

  _onDone() {
    List<PersonEntry> entries = [];
    for (int i = 0; i < cards.length; i++) {
      var name = nameTECs[i].text;
      var age = ageTECs[i].text;
      var job = jobTECs[i].text;
      entries.add(PersonEntry(name, age, job));
    }
    Navigator.pop(context, entries);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Column(
        children: <Widget>[
          Expanded(
            child: ListView.builder(
              itemCount: cards.length,
              itemBuilder: (BuildContext context, int index) {
                return cards[index];
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: RaisedButton(
              child: Text('Add new'),
              onPressed: () => setState(
                () {
                  _formKeys.add(GlobalKey<FormState>()); // add a new form key
                  cards.add(createCard());
                },
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: RaisedButton(
              child: Text('Remove last'),
              onPressed: () => setState(() {
                cards.removeLast();
                _formKeys.removeLast(); // remove the last form key
              }),
            ),
          )
        ],
      ),
      floatingActionButton: FloatingActionButton(
          child: Icon(Icons.save), onPressed: _validateInputs),
    );
  }
}

class PersonEntry {
  final String name;
  final String age;
  final String studyJob;

  PersonEntry(this.name, this.age, this.studyJob);
  @override
  String toString() {
    return 'Person: name= $name, age= $age, study job= $studyJob';
  }
}

String validatetext(String value) {
  if (value.length < 5)
    return 'More than 5 char is required';
  else
    return null;
}

RESULT: result


注:答案主要集中于解决问题GlobalKey,如果您输入Form它会更新每个值Form因为你正在使用相同的controllers为了Forms,您还可以通过创建一个来修复它List of Controllers为您TextFormFields.


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter:多个小部件使用相同的 GlobalKey 或重复的 GlobalKey 的相关文章

随机推荐