简体   繁体   中英

How to handle dynamic generated widget controller in flutter

I've one page on that page user can add the controller using the add button which is located in the app bar so if the user wants to use five times that controller then the user can add that controller and use but how can I get controller data using array. hope you understand the question.

in this code, I've added the add button and controller when user press on add button he will able add more contollers so how i handle the controllers.

Here is the code i've tried

import 'dart:io';

import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart';
import 'package:tudo/src/modules/bsp_signup/bsp_licensed_signup_terms/bsp_licensed_signup_terms_page.dart';
import 'package:tudo/src/modules/bsp_signup/bsp_signup_common_model.dart';
import 'package:tudo/src/styles/colors.dart';
import 'package:tudo/src/utils/app_constants_value.dart';

import 'package:tudo/src/utils/navigation_helper.dart';
import 'package:tudo/src/utils/validator.dart';
import 'package:tudo/src/widgets/tudo_selection_widget/TudoConditionWidget.dart';
import 'package:tudo/src/widgets/tudo_text_widget/TudoTextWidget.dart';

class BspUnlicensedSignupPage extends StatefulWidget {
  static const String routeName = "/bspUnlicensedSignup";
  final BspSignupCommonModel bspSignupCommonModel;

  BspUnlicensedSignupPage({
    Key key,
    @required this.bspSignupCommonModel,
  }) : super(key: key);

  @override
  _BspUnlicensedSignupPageState createState() =>
      _BspUnlicensedSignupPageState();
}

class _BspUnlicensedSignupPageState extends State<BspUnlicensedSignupPage> {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  List<Object> images = List<Object>();
  Future<File> _imageFile;
  @override
  void initState() {
    super.initState();

    setState(() {
      images.add("Add Image");
      images.add("Add Image");
      images.add("Add Image");
      images.add("Add Image");
      images.add("Add Image");
    });
  }

  bool informationislegitimate = false;
  DateTime expirydate1 = DateTime.now();
  DateTime expirydate2 = DateTime.now();

  final format = DateFormat("yyyy-MM-dd");
  final format2 = DateFormat("yyyy-MM-dd");
  final TextEditingController clrbusinesslicense = TextEditingController();
  final TextEditingController clrbusinesslicense2 = TextEditingController();
  final TextEditingController clrissuingauthority = TextEditingController();
  final TextEditingController clrissuingauthority2 = TextEditingController();
  String _licenseno;
  String _licenseno2;
  String _illusingauthority;
  String _illusingauthority2;
  List<String> _type2 = <String>[
    '',
    'Passport',
    'Driving License',
    'Voter ID card',
    'Ration Card',
    'Aadhar',
    'Other Id',
  ];
  String type2 = 'Passport';
  List<String> _type = <String>[
    '',
    'Passport',
    'Driving License',
    'Voter ID card',
    'Ration Card',
    'Aadhar',
    'Other Id',
  ];
  String type = 'Passport';
  Map<String, String> _formdata = {};
  var _myWidgets = List<Widget>();
  int _index = 1;

  void _add() {
    int keyValue = _index;
    _myWidgets = List.from(_myWidgets)
      ..add(Column(
        key: Key("${keyValue}"),
        children: <Widget>[
          _buildidentificationtype1(),
          _builddocumentnumber1(),
          _buildexpirydate1(),
          _buildissuingauthority1(),
          _buildidentificationpictures(),
          _buildinformationislegitmate(),
        ],
      ));

    setState(() => ++_index);
  }

  bool isClicked = false;
  _add1() {
    setState(() {
      isClicked = true;
      ++_index;
    });
  }

  Widget _buildidentificationtype1() {
    return FormBuilder(
      autovalidate: true,
      child: FormBuilderCustomField(
          attribute: "Business type",
          validators: [FormBuilderValidators.required()],
          formField: FormField(
            builder: (FormFieldState<dynamic> field) {
              return InputDecorator(
                decoration: InputDecoration(
                  prefixIcon: Icon(Icons.location_on),
                  labelText: AppConstantsValue.appConst['unlicensedsignup']
                      ['identificationtype1']['translation'],
                  hintText: AppConstantsValue.appConst['unlicensedsignup']
                      ['identificationtype1']['translation'],
                  errorText: field.errorText,
                ),
                isEmpty: type == '',
                child: new DropdownButtonHideUnderline(
                  child: new DropdownButton(
                    value: type,
                    isDense: true,
                    onChanged: (String newValue) {
                      setState(() {
                        type = newValue;
                        field.didChange(newValue);
                      });
                    },
                    items: _type.map(
                      (String value) {
                        return new DropdownMenuItem(
                          value: value,
                          child: new Text(value),
                        );
                      },
                    ).toList(),
                  ),
                ),
              );
            },
          )),
    );
  }

  Widget _builddocumentnumber1() {
    return new TudoTextWidget(
      controller: clrbusinesslicense,
      prefixIcon: Icon(FontAwesomeIcons.idCard),
      labelText: AppConstantsValue.appConst['unlicensedsignup']
          ['documentnumber1']['translation'],
      hintText: AppConstantsValue.appConst['unlicensedsignup']
          ['documentnumber1']['translation'],
      validator: Validators().validateLicenseno,
      onSaved: (val) {
        _licenseno = val;
      },
    );
  }

  Widget _buildexpirydate1() {
    return FormField(builder: (FormFieldState state) {
      return DateTimeField(
        decoration: InputDecoration(
            labelText: expirydate1.toString(),
            prefixIcon: Icon(Icons.date_range)),
        format: format,
        onShowPicker: (context, currentValue) async {
          final DateTime picked = await showDatePicker(
              context: context,
              initialDate: expirydate1,
              firstDate: DateTime(1900),
              lastDate: DateTime.now());
          if (picked != null && picked != expirydate1)
            setState(() {
              expirydate1 = picked;
              print(expirydate1);
            });
        },
      );
    });
  }

  Widget _buildissuingauthority1() {
    return new TudoTextWidget(
      prefixIcon: Icon(FontAwesomeIcons.idCard),
      labelText: AppConstantsValue.appConst['unlicensedsignup']
          ['issuingauthority1']['translation'],
      hintText: AppConstantsValue.appConst['unlicensedsignup']
          ['issuingauthority1']['translation'],
      validator: (val) => Validators.validateName(val, "Issuing Authority"),
      onSaved: (val) {
        _illusingauthority = val;
      },
      controller: clrissuingauthority,
    );
  }

  Widget _buildidentificationtype2() {
    return FormBuilder(
      autovalidate: true,
      child: FormBuilderCustomField(
          attribute: "Identification type",
          validators: [FormBuilderValidators.required()],
          formField: FormField(
            builder: (FormFieldState<dynamic> field) {
              return InputDecorator(
                decoration: InputDecoration(
                  prefixIcon: Icon(Icons.location_on),
                  labelText: AppConstantsValue.appConst['unlicensedsignup']
                      ['identificationtype2']['translation'],
                  hintText: AppConstantsValue.appConst['unlicensedsignup']
                      ['identificationtype2']['translation'],
                  errorText: field.errorText,
                ),
                isEmpty: type2 == '',
                child: new DropdownButtonHideUnderline(
                  child: new DropdownButton(
                    value: type2,
                    isDense: true,
                    onChanged: (String newValue) {
                      setState(() {
                        type2 = newValue;
                        field.didChange(newValue);
                      });
                    },
                    items: _type2.map(
                      (String value) {
                        return new DropdownMenuItem(
                          value: value,
                          child: new Text(value),
                        );
                      },
                    ).toList(),
                  ),
                ),
              );
            },
          )),
    );
  }

  Widget _builddocumentnumber2() {
    return new TudoTextWidget(
      controller: clrbusinesslicense2,
      prefixIcon: Icon(FontAwesomeIcons.idCard),
      labelText: AppConstantsValue.appConst['unlicensedsignup']
          ['documentnumber2']['translation'],
      validator: Validators().validateLicenseno,
      onSaved: (val) {
        _licenseno2 = val;
      },
    );
  }

  Widget _buildexpirydate2() {
    return FormField(builder: (FormFieldState state) {
      return DateTimeField(
        decoration: InputDecoration(
            labelText: expirydate2.toString(),
            prefixIcon: Icon(Icons.date_range)),
        format: format2,
        onShowPicker: (context, currentValue) async {
          final DateTime picked = await showDatePicker(
            context: context,
            initialDate: expirydate2,
            firstDate: DateTime(1900),
            lastDate: DateTime.now(),
          );
          if (picked != null && picked != expirydate2)
            setState(() {
              expirydate2 = picked;
              print(expirydate2);
            });
        },
      );
    });
  }

  Widget _buildissuingauthority2() {
    return new TudoTextWidget(
      controller: clrissuingauthority2,
      prefixIcon: Icon(FontAwesomeIcons.idCard),
      labelText: AppConstantsValue.appConst['unlicensedsignup']
          ['issuingauthority2']['translation'],
      validator: (val) => Validators.validateName(val, "Issuing authority"),
      onSaved: (val) {
        _illusingauthority2 = val;
      },
    );
  }

  Widget _buildidentificationpictures() {
    return GridView.count(
      shrinkWrap: true,
      crossAxisCount: 5,
      childAspectRatio: 1,
      children: List.generate(images.length, (index) {
        if (images[index] is ImageUploadModel) {
          ImageUploadModel uploadModel = images[index];
          return Card(
            clipBehavior: Clip.antiAlias,
            child: Stack(
              children: <Widget>[
                Image.file(
                  uploadModel.imageFile,
                  width: 100,
                  height: 100,
                ),
                Positioned(
                  right: 5,
                  top: 5,
                  child: InkWell(
                    child: Icon(
                      Icons.remove_circle,
                      size: 20,
                      color: Colors.red,
                    ),
                    onTap: () {
                      setState(() {
                        images.replaceRange(index, index + 1, ['Add Image']);
                      });
                    },
                  ),
                ),
              ],
            ),
          );
        } else {
          return Card(
            child: IconButton(
              icon: Icon(Icons.add),
              onPressed: () {
                _onAddImageClick(index);
              },
            ),
          );
        }
      }),
    );
  }

  Future _onAddImageClick(int index) async {
    setState(() {
      _imageFile = ImagePicker.pickImage(source: ImageSource.gallery);
      getFileImage(index);
    });
  }

  void getFileImage(int index) async {
//    var dir = await path_provider.getTemporaryDirectory();

    _imageFile.then((file) async {
      setState(() {
        ImageUploadModel imageUpload = new ImageUploadModel();
        imageUpload.isUploaded = false;
        imageUpload.uploading = false;
        imageUpload.imageFile = file;
        imageUpload.imageUrl = '';
        images.replaceRange(index, index + 1, [imageUpload]);
      });
    });
  }

  Widget _buildinformationislegitmate() {
    return TudoConditionWidget(
      text:
          "Above entered Identity information is legitimate and accurate to my knowledge",
    );
  }

  @override
  Widget build(BuildContext context) {
    final appBar = AppBar(
      title: Text("BSP Unlicensed Signup"),
      leading: IconButton(
        icon: Icon(Icons.arrow_back_ios),
        onPressed: () {
          NavigationHelper.navigatetoBack(context);
        },
      ),
      actions: <Widget>[IconButton(icon: Icon(Icons.add), onPressed: _add)],
      centerTitle: true,
    );
    final bottomNavigationBar = Container(
      color: Colors.transparent,
      height: 56,
      //margin: EdgeInsets.symmetric(vertical: 24, horizontal: 12),

      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          new FlatButton.icon(
            icon: Icon(Icons.close),
            label: Text('Clear'),
            textColor: Colors.black,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(7),
            ),
            onPressed: () {},
          ),
          new FlatButton.icon(
              icon: Icon(FontAwesomeIcons.arrowCircleRight),
              label: Text('Next'),
              color: colorStyles["primary"],
              textColor: Colors.white,
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(7),
              ),
              onPressed: () async {
                if (_formKey.currentState.validate()) {
                  BspSignupCommonModel model = widget.bspSignupCommonModel;
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => BspLicensedSignupTermsPage(
                              bspSignupCommonModel: model)));
                }
              }),
        ],
      ),
    );
    return new Scaffold(
      appBar: appBar,
      bottomNavigationBar: bottomNavigationBar,
      body: Container(
        height: double.infinity,
        width: double.infinity,
        child: Form(
          autovalidate: true,
          key: _formKey,
          child: ListView(
            padding: const EdgeInsets.all(30.0),
            children: _myWidgets,
          ),
        ),
      ),
    );
  }
}

class ImageUploadModel {
  bool isUploaded;
  bool uploading;
  File imageFile;
  String imageUrl;

  ImageUploadModel({
    this.isUploaded,
    this.uploading,
    this.imageFile,
    this.imageUrl,
  });
}

In your case you could do something like this:

final List<TextEditingController> _controllers = List();

_add() {
  TextEditingController controller = TextEditingController();
  _controllers.add(controller);
  _buildTextField(controller); // Example call
}

// Example method
Widget _buildTextField(TextEditingController controller) {
  return TextField(
    controller: controller,
  );
}

Edit: using your examṕle:

final List<TextEditingController> _controllers = List();

void _add() {
  TextEditingController controller = TextEditingController();
  _controllers.add(controller); //<--- add the new controller to the list

  int keyValue = _index;
  _myWidgets = List.from(_myWidgets)
    ..add(Column(
      key: Key("${keyValue}"),
      children: <Widget>[
        _buildidentificationtype1(),
        _builddocumentnumber1(controller), //<-- pass the new controller
        _buildexpirydate1(),
        _buildissuingauthority1(),
        _buildidentificationpictures(),
        _buildinformationislegitmate(),
      ],
    ));

  setState(() => ++_index);
}

Widget _builddocumentnumber1(TextEditingController controller) {
  return new TudoTextWidget(
    controller: controller, //<--- set the new controller
    prefixIcon: Icon(FontAwesomeIcons.idCard),
    labelText: AppConstantsValue.appConst['unlicensedsignup']
    ['documentnumber1']['translation'],
    hintText: AppConstantsValue.appConst['unlicensedsignup']
    ['documentnumber1']['translation'],
    validator: Validators().validateLicenseno,
    onSaved: (val) {
      _licenseno = val;
    },
  );
}

Edit2: If you want to access to all the values of each widget, you could put the values on a Map , using the index as key like this:

final Map<int, String> identification1Values = Map();
final Map<int, String> documentValues = Map();
final Map<int, DateTime> expiryDateValues = Map();
final Map<int, bool> isUsingAuthorityValues = Map();
final Map<int, String> identificationPicturesValues = Map();

void _add() {
  int keyValue = _index;
  _myWidgets = List.from(_myWidgets)
    ..add(Column(
      key: Key("${keyValue}"),
      children: <Widget>[
        _buildidentificationtype1(keyValue),
        _builddocumentnumber1(keyValue),
        _buildexpirydate1(keyValue),
        _buildissuingauthority1(keyValue),
        _buildidentificationpictures(keyValue),
        _buildinformationislegitmate(keyValue),
      ],
    ));

  setState(() => ++_index);
}

Then inside of each _build...() method put the values on their corresponding Map like this:

identification1Values[keyValue] = newValue;

Edit3: Make sure you assign the values inside setState()

Also you will need to have a list of controllers for each different type of text field, so inside each _build...() method you should add a new controller to it's corresponding list of controllers, like this:

final List<TextEditingController> _documentControllers = List();
final List<TextEditingController> _isUsingAuthorityControllers = List();

Widget _builddocumentnumber1(){
  TextEditingController controller = TextEditingController();
  _documentControllers.add(controller);
  return new TudoTextWidget(
    controller: controller,
    ...
  );
}

Widget _buildissuingauthority1() {
  TextEditingController controller = TextEditingController();
  _isUsingAuthorityControllers.add(controller);
  return new TudoTextWidget(
    ...
    controller: controller,
  );
}

Suggestions:

  • I recommend you to create a class containing all the properties corresponding to the values and then just use one Map to put these objects filled with all the properties.
  • You could create a custom widget that contains all the widgets you add on each click on the add button
  • Instead of keeping a list of widgets, you could just build the widgets based on the values of the Map

Create list of widgets and loop through all widgets as below to get values from widget

for (var i = 0; i < _myWidgets.length; i++) {
                String document = _documentControllers[i].text;
                String issuingAuthorityType = _issuingauthoritytype[i].text;
                String expiryDate = _expiryDate[i].text;
                String issuingAuthority = _issuingauthority[i].text;

                print(
                    'Document: $document\nIssuingAuthorityType: $issuingAuthorityType'
                    '\nExpiryDate: $expiryDate\nIssuingAuthority: $issuingAuthority'
                    '\nPicture: ${_identificationpictures.length}');
              }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM