I have custom form to upload files (code below)(I shortened the code for ease of understanding).
class CustomImageFormField extends StatelessWidget {
CustomImageFormField(
{Key? key, required this.validator, required this.onChanged,}) : super(key: key);
final String? Function(File?) validator;
final Function(File) onChanged;
File? _pickedFile;
@override
Widget build(BuildContext context) {
return FormField<File>(
validator: validator,
builder: (formFieldState) {
return Column(
children: [
GestureDetector(
onTap: () async {
FilePickerResult? file = await FilePicker.platform
.pickFiles(type: FileType.image, allowMultiple: true);
if (file != null) {
_pickedFile = File(file.files.first.path!);
onChanged.call(_pickedFile!);
}
},
),
if (formFieldState.hasError)
Padding(
padding: const EdgeInsets.only(left: 8, top: 10),
child: Text(
formFieldState.errorText!,
style: TextStyle(
fontStyle: FontStyle.normal,
fontSize: 13,
color: Colors.red[700],
height: 0.5),
),
)
],
);
});
}
}
And there is a class that uses CustomImageFormField with other form fields (code below).
class _FormForDeviceService extends State {
final _formKey = GlobalKey<FormState>();
Widget build(BuildContext context) {
return Container(padding: const EdgeInsets.all(10.0),
child: Form(key: _formKey, child: Column(children: <Widget>[
new Text('What is problem', style: TextStyle(fontSize: 20.0),),
new TextFormField(decoration: const InputDecoration(
hintText: 'Describe the problem',),
validator: (value){if (value!.isEmpty) return 'Please, describe the problem ';}),
new SizedBox(height: 20.0),
CustomImageFormField(
validator: (val) {},
onChanged: (_file) {},
),
ElevatedButton(
onPressed: (){if(_formKey.currentState!.validate()) {_formKey.currentState?.reset();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Form completed successfully',
style: TextStyle(color: Colors.black),),
backgroundColor: Colors.yellow,));
}},
child: const Text('Submit', style: TextStyle(color: Colors.black),),
style: ButtonStyle(backgroundColor: MaterialStateProperty.all(Colors.yellow)),)
],)));
}
}
My problem is that I click 'Upload Image', select files, and they load immediately. But I would like:
- so that the name of the selected files can be displayed in the form (with the ability to delete an incorrectly selected file)
- and that they would be loaded only after applying the button 'Submit'
CodePudding user response:
You'll need to add the file.files.first.path!
to a List (or better, add all picked files using images.addAll(file.files.map((file) => file.path!))
). Show each item in the list with a delete button next to it and when you press delete, you remove said item from the list.
Once you press submit, you then iterate over the list using a map and call the onChanged with that list.
_pickedFiles = images.map((path) => File(path)).toList();
onChanged.call(_pickedFiles);
CodePudding user response:
First create an empty array to store your image files:
var _images = [];
When calling onTap() function, you have to call all paths instead just one:
onTap: () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
allowMultiple: true,
type: FileType.image,
);
if (file != null) {
for (String? path in result.paths) {
File file = File(path!);
_images.add(file);
}
// Here your onChanged() function is returning just one image
}
}
Then create a listview builder to show all the images:
ListView.builder(
itemCount: _images.length,
shrinkwrap: true, // Remove if not needed, performance improves
itemBuilder: (_,i){
return Image.file(
_images[i],
fit: BoxFit.cover,
);
}
);
NOTE: Improve your code format, it's easier and faster for developers to read.