{"id":18737288,"url":"https://github.com/shubham16g/multi_image_picker_view","last_synced_at":"2026-03-27T06:28:08.691Z","repository":{"id":43959656,"uuid":"511801495","full_name":"shubham16g/multi_image_picker_view","owner":"shubham16g","description":"An image_picker based widget which helps to pick multiple images in a GridView which can also be reorderable.","archived":false,"fork":false,"pushed_at":"2024-12-28T12:29:32.000Z","size":1762,"stargazers_count":25,"open_issues_count":3,"forks_count":27,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-12-28T13:23:29.631Z","etag":null,"topics":["dart","dartlang","dartlanguage","flutter","flutter-package","flutter-ui","flutterpackage","grid-view","gridview","image-picker-library","imagepicker","reorderable"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/multi_image_picker_view","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shubham16g.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-07-08T07:20:06.000Z","updated_at":"2024-12-28T12:27:57.000Z","dependencies_parsed_at":"2023-12-17T10:28:36.129Z","dependency_job_id":"efce32a9-5ea2-4e59-99aa-0860f8c3a122","html_url":"https://github.com/shubham16g/multi_image_picker_view","commit_stats":{"total_commits":152,"total_committers":15,"mean_commits":"10.133333333333333","dds":"0.20394736842105265","last_synced_commit":"8837dae9e3d5650e8fb28bdfc4fccf3cf7e045e2"},"previous_names":["shubham16g/multi_image_picker_view"],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shubham16g%2Fmulti_image_picker_view","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shubham16g%2Fmulti_image_picker_view/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shubham16g%2Fmulti_image_picker_view/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shubham16g%2Fmulti_image_picker_view/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shubham16g","download_url":"https://codeload.github.com/shubham16g/multi_image_picker_view/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":231786792,"owners_count":18426545,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dart","dartlang","dartlanguage","flutter","flutter-package","flutter-ui","flutterpackage","grid-view","gridview","image-picker-library","imagepicker","reorderable"],"created_at":"2024-11-07T15:24:33.783Z","updated_at":"2026-03-27T06:28:08.353Z","avatar_url":"https://github.com/shubham16g.png","language":"Dart","funding_links":["https://www.buymeacoffee.com/shubhamgupta16"],"categories":[],"sub_categories":[],"readme":"# Multi Image Picker View Flutter\n\n[![](https://img.shields.io/pub/v/multi_image_picker_view.svg?color=blue\u0026label=pub.dev\u0026logo=dart\u0026logoColor=0099ff)](https://pub.dev/packages/multi_image_picker_view)\n[![](https://img.shields.io/github/issues/shubham-gupta-16/multi_image_picker_view?color=red\u0026label=Issues)](https://github.com/shubham-gupta-16/multi_image_picker_view/issues)\n[![](https://img.shields.io/github/license/shubham-gupta-16/multi_image_picker_view?label=License)]()\n\nA 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.\n\n**🚀 LIVE DEMO OF EXAMPLE PROJECT:** https://shubham16g.github.io/multi_image_picker_view/\n\n![preview](https://user-images.githubusercontent.com/55009858/178099543-d3b576d9-625c-426e-b627-9e48c2f65c17.gif)\n\n## Features\n\n- Pick multiple images\n- Displayed in GridView\n- Reorder picked images just by dragging\n- Remove picked image\n- Limit max images\n- Fully customizable UI\n\n## Getting started\n```console\nflutter pub add multi_image_picker_view\n```\nFor image/file picker\n```console\nflutter pub add image_picker\n```\nOR\n```console\nflutter pub add file_picker\n```\nOR you can use any plugin to pick images/files.\n\n### pubspec.yaml\n```yaml\n  multi_image_picker_view: # latest version\n\n  image_picker: ^1.0.4\n#  or\n  file_picker: ^6.1.1\n```\n\n## Usage\n\n### Define the controller\n```dart\nfinal controller = MultiImagePickerController(\n    picker: (int pickCount, Object? params) async {\n      // use image_picker or file_picker to pick images `pickImages`\n      // use pickCount to pass as limit to the picker. Don't need to limit as it is handled internally.\n      // params are the extras that can be pass if you are calling `controller.pickImages(params: yourParams)` manually.\n      final pickedImages = await pickImages(pickCount);\n      // convert the picked image list to `ImageFile` list and return it.\n      return pickedImages.map((e) =\u003e convertToImageFile(e)).toList();\n    }\n);\n```\nOR\n```dart\nfinal controller = MultiImagePickerController(\n    maxImages: 15,\n    images: \u003cImageFile\u003e[], // array of pre/default selected images\n    picker: (int pickCount, Object? params) async {\n      return await pickConvertedImages(allowMultiple);\n    },\n);\n```\n\n### UI Implementation\n```dart\nMultiImagePickerView(\n  controller: controller,\n  padding: const EdgeInsets.all(10),\n);\n```\nOR\n```dart\nMultiImagePickerView(\n  controller: controller,\n  bulder: (BuldContext context, ImageFile imageFile) {\n    // here returning DefaultDraggableItemWidget. You can also return your custom widget as well.\n    return DefaultDraggableItemWidget(\n      imageFile: imageFile,\n      boxDecoration:\n        BoxDecoration(borderRadius: BorderRadius.circular(20)),\n      closeButtonAlignment: Alignment.topLeft,\n      fit: BoxFit.cover,\n      closeButtonIcon:\n        const Icon(Icons.delete_rounded, color: Colors.red),\n      closeButtonBoxDecoration: null,\n      showCloseButton: true,\n      closeButtonMargin: const EdgeInsets.all(3),\n      closeButtonPadding: const EdgeInsets.all(3),\n    );\n  },\n  initialWidget: DefaultInitialWidget(\n    centerWidget: Icon(Icons.image_search_outlined),\n    backgroundColor: Theme.of(context).colorScheme.secondary.withOpacity(0.05),\n    margin: EdgeInsets.zero,\n  ), // Use any Widget or DefaultInitialWidget. Use null to hide initial widget\n  addMoreButton: DefaultAddMoreWidget(\n    icon: Icon(Icons.image_search_outlined),\n    backgroundColor: Theme.of(context).colorScheme.primaryColor.withOpacity(0.2),\n  ), // Use any Widget or DefaultAddMoreWidget. Use null to hide add more button.\n  gridDelegate: /* Your SliverGridDelegate */,\n  draggable: /* true or false, images can be reordered by dragging by user or not, default true */,\n  shrinkWrap: /* true or false, to control GridView's shrinkWrap */\n  longPressDelayMilliseconds: /* time to press and hold to start dragging item */\n  onDragBoxDecoration: /* BoxDecoration when item is dragging */,\n  padding: /* GridView padding */\n  \n);\n```\n### ImageFile\nThis 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: \n```dart\nfinal imageFile = ImageFile(\n  UniqueKey().toString(), // A unique key required to track it in grid view.\n  name: fileName,\n  extension: fileExtension,\n  path: fileFullPath,\n);\n```\n\u003e **Note:** The package have two Extension functions to convert `XFile` (`image_picker` plugin) and `PlatformFile` (`image_picker` plugin) to `ImageFile` object.\n\u003e `final imageFile = convertXFileToImageFile(xFileObject);` and `final imageFile = convertPlatformFileToImageFile(platformFileObject);`. This functions will help you to write your picker logic easily.\n\n### ImageFileView\nThe `ImageFileView` is a widget which is used to display Image using `ImageFile` object. This will work on web as well as mobile platforms.\n```dart\nchild: ImageFileView(imageFile: imageFile),\n```\n\n```dart\nchild: ImageFileView(\n  imageFile: imageFile,\n  borderRadius: BorderRadius.circular(8),\n  fit: BoxFit.cover,\n  backgroundColor: Theme.of(context).colorScheme.background,\n  errorBuilder: (BuildContext context, Object error, StackTrace? trace) {\n    return MyCustomErrorWidget(imageFile: imageFile)\n  } // if errorBuilder is null, default error widget is used.\n),\n```\n\n### Custom UI\n**GridView Draggable item**\n- In builder, you can use either `DefaultDraggableItemWidget` or your full custom Widget. i.e.\n```dart\nbuilder: (context, imageFile) {\n  return Stack(\n    children: [\n      Positioned.fill(child: ImageFileView(imageFile: imageFile)),\n      Positioned(\n        top: 4,\n        right: 4,\n        child: DraggableItemInkWell(\n          borderRadius: BorderRadius.circular(2),\n          onPressed: () =\u003e controller.removeImage(imageFile),\n          child: Container(\n            padding: const EdgeInsets.all(5),\n            decoration: BoxDecoration(\n              color: Theme.of(context).colorScheme.secondary.withOpacity(0.4),\n              shape: BoxShape.circle,\n            ),\n            child: Icon(\n              Icons.delete_forever_rounded,\n              size: 18,\n              color: Theme.of(context).colorScheme.background,\n            ),\n          ),\n        ),\n      ),\n    ],\n  );\n},\n```\n- The `DraggableItemInkWell` can be used instead of `InkWell` inside `builder` to handle proper clicks when using laptop touchpads.\n- `ImageFileView` is a custom widget to show the image using `ImageFile`.\n\n**Initial Widget**\n- You can use either `DefaultInitialWidget` or Custom widget or null if you don't want to show initial widget.\n```dart\ninitialWidget: DefaultInitialWidget(\n  centerWidget: Icon(Icons.image_search_outlined),\n  backgroundColor: Theme.of(context).colorScheme.secondary.withOpacity(0.05),\n  margin: EdgeInsets.zero,\n),\n```\nOR\n```dart\ninitialWidget: SizedBox(\n  height: 170,\n  width: double.infinity,\n  child: Center(\n    child: ElevatedButton(\n      child: const Text('Add Images'),\n      onPressed: () {\n        controller.pickImages();\n      },\n    ),\n  ),\n),\n```\nOR\n```dart\ninitialWidget: null,\n```\n\n**Initial Widget**\n- You can use either `DefaultInitialWidget` or Custom widget or null if you don't want to show initial widget.\n```dart\naddMoreButton: DefaultAddMoreWidget(\n  icon: Icon(Icons.image_search_outlined),\n  backgroundColor: Theme.of(context).colorScheme.primary.withOpacity(0.2),\n),\n```\nOR\n```dart\naddMoreButton: SizedBox(\n  height: 170,\n  width: double.infinity,\n  child: Center(\n    child: TextButton(\n      style: TextButton.styleFrom(\n        backgroundColor: Colors.blue.withOpacity(0.2),\n        shape: const CircleBorder(),\n      ),\n      onPressed: controller.pickImages,\n      child: const Padding(\n        padding: EdgeInsets.all(10),\n        child: Icon(\n          Icons.add,\n          color: Colors.blue,\n          size: 30,\n        ),\n      ),\n    ),\n  ),\n),\n```\nOR\n```dart\naddMoreButton: null,\n```\n\n### Get Picked Images\nPicked Images can be get from controller.\n```dart\nfinal images = controller.images; // return Iterable\u003cImageFile\u003e\nfor (final image in images) {\n  if (image.hasPath)\n    request.addFile(File(image.path!));\n  else \n    request.addFile(File.fromRawPath(image.bytes!));\n}\nrequest.send();\n```\nAlso controller can perform more actions.\n```dart\ncontroller.pickImages();\ncontroller.hasNoImages; // return bool\ncontroller.maxImages; // return maxImages\ncontroller.removeImage(imageFile); // remove image from the images\ncontroller.clearImages(); // remove all images (clear selection)\ncontroller.reOrderImage(oldIndex, newIndex); // reorder the image\n```\n\n## Custom Examples\n\u003e Check the example to access all the custom examples.\n\n![custom](https://user-images.githubusercontent.com/55009858/178099563-72e26aea-0a06-43c2-8315-25c7a0d039fb.gif)\n\n## Migrating `\u003c1.0.0` to `\u003e=1.0.0`\n\n### Changes in `MultiImagePickerController`\n- 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 `picker` in `MultiImagePickerController`.\n- `allowedImageTypes` removed.\n- `withData` removed.\n- `withReadStream` removed.\n\n### Changes in `MultiImagePickerView`\n- `addMoreBuilder` is removed. Now use `addMoreButton` to define your custom Add More Button.\n- `showAddMoreButton` is removed. To hide the default Add More Button, pass `null` in `addMoreButton` field.\n- `initialContainerBuilder` is removed. Now use `initialWidget` to define your custom Initial Widget.\n- `showInitialContainer` is removed. To hide the default Initial Widget, pass `null` in `initialWidget` field.\n- `itemBuilder` is removed. Now use `builder` to define your custom Draggable item widget. You can now define different widget for different image (`ImaegFile`).\n- `addMoreButtonTitle` is removed. Use `addMoreButton` and pass `DefaultAddMoreWidget` with custom parameters.\n- `addButtonTitle` is removed. Use `initialWidget` and pass `DefaultInitialWidget` with custom parameters.\n- `longPressDelayMilliseconds` is added. This is used to define the press and hold duration to start dragging.\n- `onChange` is removed.\n- `MultiImagePickerView.of(context)` can be used inside anywhere in MultiImagePickerView get the instance of it's components. i.e. `MultiImagePickerView.of(context).controller.pickImages()`.\n\n## My other flutter packages\n- \u003ca href=\"https://pub.dev/packages/view_model_x\"\u003eview_model_x\u003c/a\u003e - An Android similar state management package (StateFlow and SharedFlow with ViewModel) which helps to implement MVVM pattern easily.\n\n## Support\n\u003cp\u003e\u003ca href=\"https://www.buymeacoffee.com/shubhamgupta16\"\u003e \u003cimg align=\"center\" src=\"https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png\" height=\"50\" width=\"210\" alt=\"shubhamgupta16\" /\u003e\u003c/a\u003e\u003c/p\u003e\n\n## Contributors\n\u003ca href=\"https://github.com/shubham-gupta-16/multi_image_picker_view/graphs/contributors\"\u003e\n  \u003cimg src=\"https://contrib.rocks/image?repo=shubham-gupta-16/multi_image_picker_view\" /\u003e\n\u003c/a\u003e\n\n## Contributing\n\nPull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshubham16g%2Fmulti_image_picker_view","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshubham16g%2Fmulti_image_picker_view","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshubham16g%2Fmulti_image_picker_view/lists"}