Language: English | ไธญๆ็ฎไฝ
An assets picker which looks like the one in WeChat, based on photo_manager
for asset implementation, extended_image
for image preview, provider
to help controlling the state of the picker.
- ๐ 99% simillar to WeChat style.
- ๐ Support multi assets pick.
- ๐ Support asset preview. (Image / Video)
- Image asset support
- HEIC/HEIF Image type support
- Video asset support
- Audio asset support
- Single asset mode
- i18n support
- Custom text delegate support
- Custom theme entirely
- MacOS support
Althought the package provide selection for assets, it still require users build their own methods to handle display/upload, etc. If you have any question about how to build it, please run the example or refer to photo_manager for API usage.
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';
You need at lease three permissions: INTERNET
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
.
Then the main project needs implementation of AppGlideModule
. For example:
example/android/app/build.gradle
:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
+ apply plugin: 'kotlin-kapt'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+ implementation 'com.github.bumptech.glide:glide:4.11.0'
+ kapt 'com.github.bumptech.glide:compiler:4.11.0'
testImplementation 'junit:junit:4.12'
}
example/android/app/src/main/kotlin/com/example/exampleapp/ExampleAppGlideModule.java
:
package com.example.exampleapp;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;
@GlideModule
public class ExampleAppGlideModule extends AppGlideModule {
}
If you're using different versions of Glide
, please add this to the build.gradle
:
rootProject.allprojects {
subprojects {
project.configurations.all {
resolutionStrategy.eachDependency { details ->
if (details.requested.group == 'com.github.bumptech.glide'
&& details.requested.name.contains('glide')) {
details.useVersion "4.11.0"
}
}
}
}
}
Add following content to info.plist
.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSPhotoLibraryUsageDescription</key>
<string>Replace with your permission description.</string>
Name | Type | Description | Default |
---|---|---|---|
context | BuildContext |
Context for navigator push. | null |
maxAssets | int |
Maximum asset that the picker can pick. | 9 |
pageSize | int |
Assets amount when assets loaded with paging. Must be a multiple of gridCount . Nullable for non paging. |
320 (80 * 4) |
pathThumbSize | int |
The size of thumb data in picker. | 80 |
gridCount | int |
Grid count in picker. | 4 |
requestType | RequestType |
Request type for picker. | RequestType.image |
selectedAssets | List<AssetEntity> |
Selected assets. Prevent duplicate selection. If you don't need to prevent duplicate selection, just don't pass it. | null |
themeColor | Color |
Main theme color for the picker | Color(0xff00bc56) |
pickerTheme | ThemeData |
Theme data provider for the picker and the viewer. | null |
textDelegate | TextDelegate |
Text delegate for the picker, for customize the texts. | DefaultTextDelegate() |
routeCurve | Curve |
The curve which the picker use to build page route transition. | Curves.easeIn |
routeDuration | Duration |
The duration which the picker use to build page route transition. | const Duration(milliseconds: 500) |
typeExclusive | bool |
The Asstes type mutually exclusive | false |
notSelectableFilter | NotSelectableFilter |
Not Selectable Filter | null |
final List<AssetEntity> assets = await AssetPicker.pickAssets(context);
or
AssetPicker.pickAsset(context).then((List<AssetEntity> assets) {
/.../
});
List<AssetEntity> assets = <AssetEntity>{};
final List<AssetEntity> result = await AssetPicker.pickAssets(
context,
maxAssets: 9,
pageSize: 320,
pathThumbSize: 80,
gridCount: 4,
requestType: RequestType.image,
selectedAssets: assets,
themeColor: Colors.cyan,
pickerTheme: ThemeData.dark(), // This cannot be set when the `themeColor` was provided.
textDelegate: DefaultTextDelegate(),
routeCurve: Curves.easeIn,
routeDuration: const Duration(milliseconds: 500),
typeExclusive: true, // add +
notSelectableFilter: (AssetEntity asset, List<AssetEntity> selectedAssets, bool notSelectable){
if(selectedAssets.isNotEmpty && selectedAssets[0].type == AssetType.video){
return !notSelectable && selectedAssets.length >= videoLimit;
}
return notSelectable;
}
);
or
List<AssetEntity> assets = <AssetEntity>{};
int videoLimit = 1; // Select video limit
AssetPicker.pickAssets(
context,
maxAssets: 9,
pageSize: 320,
pathThumbSize: 80,
gridCount: 4,
requestType: RequestType.image,
selectedAssets: assets,
themeColor: Colors.cyan,
pickerTheme: ThemeData.dark(), // This cannot be set when the `themeColor` was provided.
textDelegate: DefaultTextDelegate(),
routeCurve: Curves.easeIn,
routeDuration: const Duration(milliseconds: 500),
typeExclusive: false, // add +
selectableFilter: (AssetEntity asset, List<AssetEntity> selectedAssets, bool disable){
if(selectedAssets.isNotEmpty && selectedAssets[0].type == AssetType.video){
return !disable && selectedAssets.length >= videoLimit;
}
return disable;
}
).then((List<AssetEntity> assets) {
/.../
});
AssetPicker.registerObserve(); // Register callback.
AssetPicker.unregisterObserve(); // Unregister callback.
In order to combine this package with camera shooting or something related, there's a wordaround about how to create an AssetEntity
with File
or Uint8List
object.
final File file = your_file; // Your file object
final Uint8List byteData = await file.readAsBytes(); // Convert to Uint8List
final AssetEntity imageEntity = await PhotoManager.editor.saveImage(byteData); // Saved in the device then create an AssetEntity
If you don't want to keep the asset in your device, just delete it after you complete with your process (upload, editing, etc).
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 complie 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.