Language: English | δΈζ
An assets picker which based on the WeChat's UI,
using photo_manager
for asset implementation,
extended_image
for image preview,
and provider
to help control the state of the picker.
To take a photo or a video for assets, please check the detailed usage in the example, and head over to wechat_camera_picker.
Current WeChat version that UI based on: 8.x UI designs will be updated following the WeChat update in anytime.
- Migration Guide
- Features
- Screenshots
- Preparing for use
- Usage
- Frequently asked question
- Execution failed for task ':photo_manager:compileDebugKotlin'
- How can I get path from the
AssetEntity
to integrate withFile
object, upload or edit? - How can I change the name of "Recent" or other entities name/properties?
- Create
AssetEntity
fromFile
orUint8List
(rawData) - Console warning 'Failed to find GeneratedAppGlideModule'
- Disable
ACCESS_MEDIA_LOCATION
permission
See Migration Guide.
- β»οΈ Fully implementable with delegates override
- π 99% similar to WeChat style
- β‘οΈ Adjustable performance according to parameters
- π· Image asset support
- π¬ HEIF Image type support
- π₯ Video asset support
- πΆ Audio asset support
- 1οΈβ£ Single asset mode
- π± i18n support
- βͺ RTL language support
- β Special item builder (prepend/append) support
- π Custom sort path delegate support
- π Custom text delegate support
- β³ Custom filter options support (
photo_manager
) - π Fully customizable theme
- π» macOS support
Although the package provides assets selection, it still requires users to build their own methods to handle upload, image compress, etc. If you have any questions about how to build them, please run the example or refer to photo_manager for API usage.
<2.5.0 | 2.8.0 | 2.10.0 | |
---|---|---|---|
7.0.0+ | β | β | β |
6.3.0+ | β | β | β |
If you got a resolve conflict
error when running flutter pub get
,
please use dependency_overrides
to fix it.
Add wechat_assets_picker
to pubspec.yaml
dependencies.
dependencies:
wechat_assets_picker: ^latest_version
Then import the package in your code:
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
Required permissions: INTERNET
, READ_EXTERNAL_STORAGE
, WRITE_EXTERNAL_STORAGE
, ACCESS_MEDIA_LOCATION
.
If you don't need the ACCESS_MEDIA_LOCATION
permission,
see Disable ACCESS_MEDIA_LOCATION
permission.
If you found some warning logs with Glide
appearing,
then the main project needs an implementation of AppGlideModule
.
See Generated API.
- Platform version has to be at least 9.0. Modify
ios/Podfile
and update accordingly.
platform :ios, '9.0'
- Add the following content to
info.plist
.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSPhotoLibraryUsageDescription</key>
<string>Replace with your permission description.</string>
- Platform version has to be at least 10.15. Modify
macos/Podfile
and update accordingly.
platform :osx, '10.15'
-
Set the minimum deployment target to 10.15. Use XCode to open
macos/Runner.xcworkspace
. -
Follow the iOS instructions and modify
info.plist
accordingly.
final List<AssetEntity>? result = await AssetPicker.pickAssets(context);
Use AssetPickerConfig
for more picking behaviors.
final List<AssetEntity>? result = await AssetPicker.pickAssets(
context,
pickerConfig: const AssetPickerConfig(),
);
Fields in AssetPickerConfig
:
Name | Type | Description | Default |
---|---|---|---|
selectedAssets | List<AssetEntity>? |
Selected assets. Prevent duplicate selection. | null |
maxAssets | int |
Maximum asset that the picker can pick. | 9 |
pageSize | int? |
Number of assets per page. Must be a multiple of gridCount . |
80 |
gridThumbnailSize | ThumbnailSize |
Thumbnail size for the grid's item. | ThumbnailSize.square(200) |
pathThumbnailSize | ThumbnailSize |
Thumbnail size for the path selector. | ThumbnailSize.square(80) |
previewThumbnailSize | ThumbnailSize? |
Preview thumbnail size in the viewer. | null |
requestType | RequestType |
Request type for picker. | RequestType.common |
specialPickerType | SpacialPickerType? |
Provides the option to integrate a custom picker type. | null |
keepScrollOffset | bool |
Whether the picker should save the scroll offset between pushes and pops. | null |
sortPathDelegate | SortPathDelegate<AssetPathEntity>? |
Path entities sort delegate for the picker, sort paths as you want. | CommonSortPathDelegate |
filterOptions | FilterOptionGroup? |
Allow users to customize assets filter options. | null |
gridCount | int |
Grid count in picker. | 4 |
themeColor | Color? |
Main theme color for the picker. | Color(0xff00bc56) |
pickerTheme | ThemeData? |
Theme data provider for the picker and the viewer. | null |
textDelegate | AssetPickerTextDelegate? |
Text delegate for the picker, for customize the texts. | AssetPickerTextDelegate() |
specialItemPosition | SpecialItemPosition |
Allow users set a special item in the picker with several positions. | SpecialItemPosition.none |
specialItemBuilder | SpecialItemBuilder? |
The widget builder for the special item. | null |
loadingIndicatorBuilder | IndicatorBuilder? |
Indicates the loading status for the builder. | null |
selectPredicate | AssetSelectPredicate |
Predicate whether an asset can be selected or unselected. | null |
shouldRevertGrid | bool? |
Whether the assets grid should revert. | null |
TL;DR, we've put multiple common usage with the packages into the example.
You can use the keepScrollOffset
feature only with the pickAssetsWithDelegate
method.
See the Keep scroll offset
pick method in the example for how to implement it.
For more details about custom delegates,
head over to example/lib/customs
.
You can both found List<PickMethod> pickMethods
in
example/lib/pages/multi_assets_page.dart
and example/lib/pages/single_assets_page.dart
,
which provide methods in multiple picking and single picking mode.
Assets will be stored temporary and displayed at the below of the page.
The maximum assets limit is 9
in the multiple picking page,
and you can modify it as you wish.
Some methods can only work with multiple mode, such as "WeChat Moment".
Only one and maximum to one asset can be picked at once.
You can try custom pickers with the "Custom" page.
We've defined a picker that integrates with Directory
and File
(completely out of the photo_manager
scope),
and a picker with multiple tabs switching.
You can submit PRs to create your own implementation
if you found your implementation might be useful for others.
See [Contribute custom implementations][lib/customs/CONTRIBUTING.md]
for more details.
The AssetEntityImageProvider
can display the thumb image of images & videos, and the original data of image.
Use it like a common ImageProvider
.
Image(image: AssetEntityImageProvider(asset, isOriginal: false))
Check the example for how it displays.
AssetPicker.registerObserve(); // Register callback.
AssetPicker.unregisterObserve(); // Unregister callback.
AssetPickerBuilderDelegate
, AssetPickerViewerBuilderDelegate
, AssetPickerProvider
and
AssetPickerViewerProvider
are all exposed and overridable. You can extend them and use your own
type with generic type <A: Asset, P: Path>
, then implement abstract methods. See the Custom
page
in the example which has an implementation based on <File, Directory>
types.
See photo_manager#561 for more details.
You don't need it (might be).
You can always request the File
object with
entity.file
or entity.originFile
,
and entity.originBytes
for Uint8List
.
If you still need path after requested the File
, get it through file.path
.
final File file = await entity.file; // Thumbnails or edited files.
final File originFile = await entity.originFile; // Original files.
final String path = file.path;
final String originPath = originFile.path;
The path entity called "Recent", brought by photo_manager
in the path entities list,
includes all AssetEntity
on your device.
"Recent" is a system named entity in most platforms.
While we provided ability to customize the text delegate,
the name/properties can only be updated with SortPathDelegate
.
This is the only way that you have access to all path entities,
or the only way that we exposed currently.
To change the name of the path entity, extend the CommonSortPathDelegate
with your own delegate,
then write something like the code below:
/// Create your own sort path delegate.
class CustomSortPathDelegate extends CommonSortPathDelegate {
const CustomSortPathDelegate();
@override
void sort(List<AssetPathEntity> list) {
///...///
// In here you can check every path entities if you want.
// The only property we recommend to change is [name],
// And we have no responsibility for issues caused by
// other properties update.
for (final AssetPathEntity entity in list) {
// If the entity `isAll`, that's the "Recent" entity you want.
if (entity.isAll) {
entity.name = 'Whatever you want';
}
}
///...///
}
}
Pass the delegate through the static call method, then you will get a self-named path entity.
In order to combine this package with camera shooting or something related,
there's a solution about how to create an AssetEntity
with File
or Uint8List
object.
final File file = your_file; // Your `File` object
final String path = file.path;
final AssetEntity fileEntity = await PhotoManager.editor.saveImageWithPath(
path,
title: basename(path),
); // Saved in the device then create an AssetEntity
final Uint8List data = your_data; // Your `Uint8List` object
final AssetEntity imageEntity = await PhotoManager.editor.saveImage(
file.path,
title: 'title_with_extension.jpg',
); // Saved in the device then create an AssetEntity
Notice: If you don't want to keep the file in your device,
use File
for operations as much as possible.
A deletion operation might call system popups with some OS:
final List<String> result = await PhotoManager.editor.deleteWithIds([entity.id]);
ref: flutter_photo_manager#insert-new-item
W/Glide (21133): Failed to find GeneratedAppGlideModule. You should include an annotationProcessor compile dependency on com.github.bumptech.glide:compiler in you application ana a @GlideModule annotated AppGlideModule implementation or LibraryGlideModules will be silently ignored.
Glide
needs annotation to keep singleton, prevent conflict between instances and versions,
so while the photo manager uses Glide
to implement image features,
the project which import this should define its own AppGlideModule
.
See Android section for implementation.
Android contains ACCESS_MEDIA_LOCATION
permission by default.
This permission is introduced in Android Q.
If your app doesn't need the permission,
you need to add the following node to the AndroidManifest.xml
in your app:
<uses-permission
android:name="android.permission.ACCESS_MEDIA_LOCATION"
tools:node="remove"
/>
Many thanks to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcomed!!
Every aspect of IntelliJ IDEA has been designed to maximize developer productivity. Together, intelligent coding assistance and ergonomic design make development not only productive but also enjoyable.
Thanks to JetBrains for allocating free open-source licenses for IDEs such as IntelliJ IDEA.