multi_image_picker_view 3.0.0
multi_image_picker_view: ^3.0.0 copied to clipboard
A complete widget which can easily pick multiple images from device and display them in UI. Also picked image can be re-ordered and removed easily.
Multi Image Picker View Flutter #
A complete widget which can easily pick multiple images from device and display them in UI. Also picked image can be re-ordered and removed easily.
🚀 LIVE DEMO OF EXAMPLE PROJECT: https://shubham16g.github.io/multi_image_picker_view/

Features #
- Pick multiple images
- Displayed in GridView
- Reorder picked images just by dragging
- Remove picked image
- Limit max images
- Fully customizable UI
Getting started #
flutter pub add multi_image_picker_view
For image/file picker
flutter pub add image_picker
OR
flutter pub add file_picker
OR you can use any plugin to pick images/files.
pubspec.yaml #
multi_image_picker_view: # latest version
image_picker: ^1.0.4
# or
file_picker: ^6.1.1
Usage #
Define the controller #
final controller = MultiImagePickerController(
picker: (int pickCount, Object? params) async {
// use image_picker or file_picker to pick images `pickImages`
// use pickCount to pass as limit to the picker. Don't need to limit as it is handled internally.
// params are the extras that can be pass if you are calling `controller.pickImages(params: yourParams)` manually.
final pickedImages = await pickImages(pickCount);
// convert the picked image list to `ImageFile` list and return it.
return pickedImages.map((e) => convertToImageFile(e)).toList();
}
);
OR
final controller = MultiImagePickerController(
maxImages: 15,
images: <ImageFile>[], // array of pre/default selected images
picker: (int pickCount, Object? params) async {
return await pickConvertedImages(allowMultiple);
},
);
UI Implementation #
MultiImagePickerView(
controller: controller,
padding: const EdgeInsets.all(10),
);
OR
MultiImagePickerView(
controller: controller,
bulder: (BuldContext context, ImageFile imageFile) {
// here returning DefaultDraggableItemWidget. You can also return your custom widget as well.
return DefaultDraggableItemWidget(
imageFile: imageFile,
boxDecoration:
BoxDecoration(borderRadius: BorderRadius.circular(20)),
closeButtonAlignment: Alignment.topLeft,
fit: BoxFit.cover,
closeButtonIcon:
const Icon(Icons.delete_rounded, color: Colors.red),
closeButtonBoxDecoration: null,
showCloseButton: true,
closeButtonMargin: const EdgeInsets.all(3),
closeButtonPadding: const EdgeInsets.all(3),
);
},
initialWidget: DefaultInitialWidget(
centerWidget: Icon(Icons.image_search_outlined),
backgroundColor: Theme.of(context).colorScheme.secondary.withOpacity(0.05),
margin: EdgeInsets.zero,
), // Use any Widget or DefaultInitialWidget. Use null to hide initial widget
addMoreButton: DefaultAddMoreWidget(
icon: Icon(Icons.image_search_outlined),
backgroundColor: Theme.of(context).colorScheme.primaryColor.withOpacity(0.2),
), // Use any Widget or DefaultAddMoreWidget. Use null to hide add more button.
gridDelegate: /* Your SliverGridDelegate */,
draggable: /* true or false, images can be reordered by dragging by user or not, default true */,
shrinkWrap: /* true or false, to control GridView's shrinkWrap */
longPressDelayMilliseconds: /* time to press and hold to start dragging item */
onDragBoxDecoration: /* BoxDecoration when item is dragging */,
padding: /* GridView padding */
);
ImageFile #
This package use ImageFile entity to represent one image or file. Inside picker method in MultiImagePickerController, pick your images/files and convert it to list of ImageFile object and then return it. The ImageFile consists of:
final imageFile = ImageFile(
UniqueKey().toString(), // A unique key required to track it in grid view.
name: fileName,
extension: fileExtension,
path: fileFullPath,
);
Note: The package have two Extension functions to convert
XFile(image_pickerplugin) andPlatformFile(image_pickerplugin) toImageFileobject.final imageFile = convertXFileToImageFile(xFileObject);andfinal imageFile = convertPlatformFileToImageFile(platformFileObject);. This functions will help you to write your picker logic easily.
ImageFileView #
The ImageFileView is a widget which is used to display Image using ImageFile object. This will work on web as well as mobile platforms.
child: ImageFileView(imageFile: imageFile),
child: ImageFileView(
imageFile: imageFile,
borderRadius: BorderRadius.circular(8),
fit: BoxFit.cover,
backgroundColor: Theme.of(context).colorScheme.background,
errorBuilder: (BuildContext context, Object error, StackTrace? trace) {
return MyCustomErrorWidget(imageFile: imageFile)
} // if errorBuilder is null, default error widget is used.
),
Custom UI #
GridView Draggable item
- In builder, you can use either
DefaultDraggableItemWidgetor your full custom Widget. i.e.
builder: (context, imageFile) {
return Stack(
children: [
Positioned.fill(child: ImageFileView(imageFile: imageFile)),
Positioned(
top: 4,
right: 4,
child: DraggableItemInkWell(
borderRadius: BorderRadius.circular(2),
onPressed: () => controller.removeImage(imageFile),
child: Container(
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.secondary.withOpacity(0.4),
shape: BoxShape.circle,
),
child: Icon(
Icons.delete_forever_rounded,
size: 18,
color: Theme.of(context).colorScheme.background,
),
),
),
),
],
);
},
- The
DraggableItemInkWellcan be used instead ofInkWellinsidebuilderto handle proper clicks when using laptop touchpads. ImageFileViewis a custom widget to show the image usingImageFile.
Initial Widget
- You can use either
DefaultInitialWidgetor Custom widget or null if you don't want to show initial widget.
initialWidget: DefaultInitialWidget(
centerWidget: Icon(Icons.image_search_outlined),
backgroundColor: Theme.of(context).colorScheme.secondary.withOpacity(0.05),
margin: EdgeInsets.zero,
),
OR
initialWidget: SizedBox(
height: 170,
width: double.infinity,
child: Center(
child: ElevatedButton(
child: const Text('Add Images'),
onPressed: () {
controller.pickImages();
},
),
),
),
OR
initialWidget: null,
Initial Widget
- You can use either
DefaultInitialWidgetor Custom widget or null if you don't want to show initial widget.
addMoreButton: DefaultAddMoreWidget(
icon: Icon(Icons.image_search_outlined),
backgroundColor: Theme.of(context).colorScheme.primary.withOpacity(0.2),
),
OR
addMoreButton: SizedBox(
height: 170,
width: double.infinity,
child: Center(
child: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.blue.withOpacity(0.2),
shape: const CircleBorder(),
),
onPressed: controller.pickImages,
child: const Padding(
padding: EdgeInsets.all(10),
child: Icon(
Icons.add,
color: Colors.blue,
size: 30,
),
),
),
),
),
OR
addMoreButton: null,
Get Picked Images #
Picked Images can be get from controller.
final images = controller.images; // return Iterable<ImageFile>
for (final image in images) {
if (image.hasPath)
request.addFile(File(image.path!));
else
request.addFile(File.fromRawPath(image.bytes!));
}
request.send();
Also controller can perform more actions.
controller.pickImages();
controller.hasNoImages; // return bool
controller.maxImages; // return maxImages
controller.removeImage(imageFile); // remove image from the images
controller.clearImages(); // remove all images (clear selection)
controller.reOrderImage(oldIndex, newIndex); // reorder the image
Custom Examples #
Check the example to access all the custom examples.

Migrating <1.0.0 to >=1.0.0 #
Changes in MultiImagePickerController #
- Inbuilt image picker is removed. You have to provide your own image/file picker logic. This will provide you more controls over image/file picking. You have to pass your
pickerinMultiImagePickerController. allowedImageTypesremoved.withDataremoved.withReadStreamremoved.
Changes in MultiImagePickerView #
addMoreBuilderis removed. Now useaddMoreButtonto define your custom Add More Button.showAddMoreButtonis removed. To hide the default Add More Button, passnullinaddMoreButtonfield.initialContainerBuilderis removed. Now useinitialWidgetto define your custom Initial Widget.showInitialContaineris removed. To hide the default Initial Widget, passnullininitialWidgetfield.itemBuilderis removed. Now usebuilderto define your custom Draggable item widget. You can now define different widget for different image (ImaegFile).addMoreButtonTitleis removed. UseaddMoreButtonand passDefaultAddMoreWidgetwith custom parameters.addButtonTitleis removed. UseinitialWidgetand passDefaultInitialWidgetwith custom parameters.longPressDelayMillisecondsis added. This is used to define the press and hold duration to start dragging.onChangeis removed.MultiImagePickerView.of(context)can be used inside anywhere in MultiImagePickerView get the instance of it's components. i.e.MultiImagePickerView.of(context).controller.pickImages().
My other flutter packages #
- view_model_x - An Android similar state management package (StateFlow and SharedFlow with ViewModel) which helps to implement MVVM pattern easily.
Support #
Contributors #
Contributing #
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

