如何在 flutter 中处理动态生成的小部件控制器
How to handle dynamic generated widget controller in flutter
我在该页面上有一个页面,用户可以使用位于应用栏中的添加按钮添加控制器,因此如果用户想要使用该控制器的五倍,则用户可以添加该控制器并使用但是如何使用数组获取控制器数据。希望你能理解这个问题。
在这段代码中,我添加了添加按钮和控制器,当用户按下添加按钮时,他将能够添加更多控制器,所以我如何处理控制器。
这是我试过的代码
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,
});
}
在你的情况下你可以这样做:
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,
);
}
编辑: 使用你的考试:
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: 如果你想访问每个小部件的所有值,你可以将值放在 Map
上,使用索引作为键,像这样:
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);
}
然后在每个 _build...()
方法中将值放在相应的 Map
上,如下所示:
identification1Values[keyValue] = newValue;
Edit3: 确保在 setState()
中分配值
此外,您还需要为每种不同类型的文本字段创建一个控制器列表,因此在每个 _build...()
方法中,您应该向其对应的控制器列表中添加一个新控制器,如下所示:
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,
);
}
建议:
- 我建议您创建一个包含所有属性的 class
对应于这些值,然后只用一个
Map
来放置这些
填充所有属性的对象。
- 您可以创建一个自定义小部件,其中包含您创建的所有小部件
每次点击添加按钮时添加
- 您可以只构建
基于
Map
值的小部件
创建小部件列表并如下遍历所有小部件以从小部件获取值
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}');
}
我在该页面上有一个页面,用户可以使用位于应用栏中的添加按钮添加控制器,因此如果用户想要使用该控制器的五倍,则用户可以添加该控制器并使用但是如何使用数组获取控制器数据。希望你能理解这个问题。
在这段代码中,我添加了添加按钮和控制器,当用户按下添加按钮时,他将能够添加更多控制器,所以我如何处理控制器。
这是我试过的代码
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,
});
}
在你的情况下你可以这样做:
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,
);
}
编辑: 使用你的考试:
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: 如果你想访问每个小部件的所有值,你可以将值放在 Map
上,使用索引作为键,像这样:
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);
}
然后在每个 _build...()
方法中将值放在相应的 Map
上,如下所示:
identification1Values[keyValue] = newValue;
Edit3: 确保在 setState()
此外,您还需要为每种不同类型的文本字段创建一个控制器列表,因此在每个 _build...()
方法中,您应该向其对应的控制器列表中添加一个新控制器,如下所示:
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,
);
}
建议:
- 我建议您创建一个包含所有属性的 class
对应于这些值,然后只用一个
Map
来放置这些 填充所有属性的对象。 - 您可以创建一个自定义小部件,其中包含您创建的所有小部件 每次点击添加按钮时添加
- 您可以只构建
基于
Map
值的小部件
创建小部件列表并如下遍历所有小部件以从小部件获取值
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}');
}