基本介绍
wechat_assets_picker 是 Flutter 社区一个很常用的 媒体选择器库,灵感来自 微信的图片/视频选择界面。它主要功能是 选择图片、视频、音频 等多媒体文件,并且支持 相册浏览、相机拍摄、多选、裁剪过滤 等功能。
它的底层基于 photo_manager 获取本地媒体资源,然后通过 类似微信风格的 UI 进行选择。
核心功能如下:
- 支持多类型媒体选择
- 图片(JPEG、PNG、GIF、WebP 等)
- 视频(mp4、mov 等,支持预览播放)
- 音频(可选,依赖系统支持)
- 选择模式
- 单选 / 多选
- 预设已选资源(编辑已选)
- 最大/最小选择数量限制
- UI 高度自定义
- 类似微信的相册风格
- 可以自定义主题、文案、图标
- 支持国际化
入门案例
安装
flutter pub add wechat_assets_picke
配置
结合 permission_handler 的 配置
Android
AndroidManifest.xml(部分版本需要按需添加):
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
如果是 Android 12 以下,还可能需要:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
iOS
ios/Runner/Info.plist:
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册来选择图片/视频</string>
ios/Podfile
## dart: PermissionGroup.photos
'PERMISSION_PHOTOS=1',
代码
import 'package:flutter/material.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
import 'package:permission_handler/permission_handler.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Wechat Picker Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const WechatPickerDemo(),
);
}
}
class WechatPickerDemo extends StatefulWidget {
const WechatPickerDemo({super.key});
@override
State<WechatPickerDemo> createState() => _WechatPickerDemoState();
}
class _WechatPickerDemoState extends State<WechatPickerDemo> {
List<AssetEntity>? selectedAssets; // 保存选择结果
/// 检查并请求权限
Future<bool> _requestPermissions() async {
// 请求相册权限
final photoStatus = await Permission.photos.request();
// 请求相机权限(如果需要用相机入口)
// final cameraStatus = await Permission.camera.request();
if (photoStatus.isGranted) {
return true;
} else {
// 引导用户去设置界面
openAppSettings();
return false;
}
}
/// 打开选择器
Future<void> _pickAssets() async {
// 检查权限:同时获取相机和相册的权限
final hasPermission = await _requestPermissions();
if (!hasPermission) return;
final result = await AssetPicker.pickAssets(
context,
pickerConfig: const AssetPickerConfig(
requestType: RequestType.image, // 只选图片
maxAssets: 5, // 最多 5 张
),
);
if (result != null) {
// 更新状态以显示选择结果
setState(() => selectedAssets = result);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Wechat Assets Picker + Permission")),
body: Center(
child: Column(
children: [
// 按钮
ElevatedButton(onPressed: _pickAssets, child: const Text("选择图片")),
// 如果选择了图片
if (selectedAssets != null)
Wrap(
children: selectedAssets!.map((e) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: AssetEntityImage(
e,
isOriginal: false,
thumbnailSize: const ThumbnailSize.square(200),
width: 100,
height: 100,
fit: BoxFit.cover,
),
);
}).toList(),
),
],
),
),
);
}
}
AssetEntityImage
是什么
AssetEntityImage 组件是 wechat_assets_picker中专门用来展示 AssetEntity(相册里的图片/视频缩略图) 的小工具。它的作用有点像 Image.file 或 Image.memory,但帮你把底层的异步加载和缩略图获取都封装好了。
AssetEntity:wechat_assets_picker/photo_manager提供的 媒体资源对象,里面包含了图片、视频、音频等文件的元信息(id、路径、类型、宽高等)。AssetEntityImage:基于AssetEntity的封装,用来直接显示缩略图或原图的 Widget。
构造函数的参数
AssetEntityImage(
AssetEntity entity, {
bool isOriginal = false, // 是否加载原图
ThumbnailSize? thumbnailSize, // 缩略图大小
double? width, // 宽度
double? height, // 高度
BoxFit fit = BoxFit.cover, // 填充模式
Alignment alignment = Alignment.center,
Color? color, // 前景色 (比如滤镜)
BlendMode? colorBlendMode, // 前景色混合模式
WidgetBuilder? errorBuilder, // 加载失败时展示的 widget
WidgetBuilder? loadingBuilder, // 加载中时展示的 widget
})
entity:你传入的AssetEntity对象,比如相册里的一张图或一个视频。isOriginalfalse(默认):显示缩略图,加载速度快,适合列表、预览用。true:显示原始图像(体积大,耗时、耗内存),一般用在全屏查看时。
thumbnailSize:控制缩略图大小,比如:thumbnailSize: const ThumbnailSize.square(200),表示生成 200x200 的正方形缩略图。
width和height: Widget 的显示尺寸(和thumbnailSize不同,这里是 Flutter UI 层的大小控制)。fit:类似于Image的BoxFit,比如:BoxFit.cover→ 填满裁剪BoxFit.contain→ 保持比例完整显示
errorBuilder/loadingBuilder:自定义加载失败或加载中时的 UI,比如显示一个占位符。
使用示例
显示缩略图(常用)
AssetEntityImage(
asset, // AssetEntity
thumbnailSize: const ThumbnailSize.square(200),
width: 100,
height: 100,
fit: BoxFit.cover,
)
thumbnailSize(缩略图像素大小):控制从系统相册/媒体库里请求出来的 图片数据的分辨率。比如:ThumbnailSize.square(200)→ 系统返回 200×200 像素 的图片数据(内存里的 Bitmap)。可以理解为“下载的图有多大”。width和height(Widget 大小):控制在 Flutter UI 中显示的 Widget 尺寸。比如:width: 100, height: 100→ 在屏幕上只占 100×100 的空间。可以理解为“显示的时候放多大”。上面配置的效果:Flutter 会请求 200×200 的图像数据(质量更好,不容易糊)。但是在界面上用 100×100 的空间显示(等于把图缩小)。
为什么不直接用 100×100?
如果
thumbnailSize设太小(比如 100×100),当你在列表里滚动时可能没问题,但放大或在高分屏设备上看,就容易模糊。一般做法:
thumbnailSize设比 Widget 显示尺寸稍大(比如 2×,200px 用来显示 100px),这样在 Retina 屏上也清晰。
显示原图(少用,适合预览大图)
AssetEntityImage(
asset,
isOriginal: true, // 原图模式
width: double.infinity,
height: double.infinity,
fit: BoxFit.contain,
)
带加载/失败占位
AssetEntityImage(
asset,
width: 100,
height: 100,
fit: BoxFit.cover,
loadingBuilder: (_) => const Center(child: CircularProgressIndicator()),
errorBuilder: (_) => const Icon(Icons.error, color: Colors.red),
)
AssetPicker
是什么
AssetPicker是wechat_assets_picker库里 调用资源选择器 UI 的静态方法集合。- 简单说:它帮你弹出一个微信风格的 相册选择器界面,并在用户选择后返回一组
AssetEntity(图片/视频等媒体资源)。 - 你不需要自己写 UI,只要调用
AssetPicker.pickAssets(...),就能获得用户选的资源。 AssetPicker会自动访问系统相册里的图片/视频文件夹(相册目录 / Albums)wechat_assets_picker的底层依赖photo_manager库。photo_manager会调用 Android MediaStore / iOS PhotoKit,去获取系统相册里所有的 相册文件夹(相册集 / album)。
核心方法
pickAssets
最常用的方法:选择图片/视频/音频。
final List<AssetEntity>? result = await AssetPicker.pickAssets(
context,
pickerConfig: const AssetPickerConfig(
requestType: RequestType.image, // 选择类型:图片/视频/音频/混合
maxAssets: 9, // 最大选择数量
),
);
- 返回值:
List<AssetEntity>?,表示用户选择的媒体资源列表(图片、视频等)。如果用户取消选择则返回null。
pickAssetsWithDelegate
高级用法,允许你传入自定义的 delegate(委托类),完全控制 UI 和交互逻辑。
final result = await AssetPicker.pickAssetsWithDelegate(
context,
delegate: MyCustomPickerDelegate(),
);
一般只在你要 自定义 UI 或 深度改造选择器 时用。
配置类:AssetPickerConfig
这是 AssetPicker 的核心参数配置,决定选择器的行为。常用参数有:
AssetPickerConfig({
this.requestType = RequestType.image, // 选择类型
this.maxAssets = 9, // 最大数量
this.selectedAssets, // 已选中的资源(编辑模式)
this.themeColor, // 主题色
this.gridCount = 4, // 网格列数
this.pageSize = 80, // 分页加载数量
this.textDelegate, // 国际化文案
this.specialPickerType, // 特殊模式,比如朋友圈
this.filterOptions, // 资源过滤,比如只显示最近3天
})
RequestType
RequestType 的可选值有如下几种:
RequestType.image // 只获取图片
RequestType.video // 只获取视频
RequestType.audio // 只获取音频
RequestType.common // 图片 + 视频
RequestType.all // 图片 + 视频 + 音频
audio:仅返回音频文件(录音、音乐等,前提是平台支持)。iOS 上可能受限,因为 iOS 的 PhotoKit 不总是允许访问音频。
SpecialPickerType
/// Provide some special picker types to integrate
/// un-common pick pattern.
/// 提供一些特殊的选择器类型以整合非常规的选择行为。
enum SpecialPickerType {
/// WeChat Moments mode.
/// 微信朋友圈模式
///
/// The user can only select *one video* or *multiple images* at the same time,
/// and those two asset types cannot be selected at the same time.
/// 用户只可以选择 **一个视频** 或 **多个图片**,并且两种类型互斥。
wechatMoment,
/// Disable preview of assets.
/// 禁用资源预览
///
/// There is no preview mode when clicking grid items.
/// In multiple select mode, any click (either on the select indicator or on
/// the asset itself) will select the asset.
/// In single select mode, any click directly selects the asset and returns.
/// 用户在点击网格的 item 时无法进入预览。
/// 在多选模式下无论点击选择指示还是 item 都将触发选择,
/// 而在单选模式下将直接返回点击的资源。
noPreview,
}
AssetEntity
AssetEntity 表示相册中一条资源的元信息 + 获取资源的方法。比如:一张图片,一段视频,一条音频
下面是 AssetEntity 的一些常见属性:
| 属性 | 类型 | 说明 |
|---|---|---|
id |
String |
系统中该资源的唯一标识 |
type |
AssetType |
资源类型(图片/视频/音频/其它) |
width / height |
int |
媒体的原始像素宽高 |
duration |
int |
视频或音频的时长(秒),图片为 0 |
createDateTime |
DateTime |
创建时间 |
modifiedDateTime |
DateTime |
修改时间 |
isFavorite |
bool |
是否收藏(仅部分平台支持) |
relativePath |
String? |
文件在系统相册中的相对路径(Android 常见,iOS 受限制) |
title |
String? |
文件名(部分平台支持) |
常用方法:
| 方法 | 返回 | 说明 |
|---|---|---|
thumbnailData |
Uint8List? |
获取缩略图数据(图片字节) |
thumbnailDataWithSize(ThumbnailSize) |
Uint8List? |
获取指定大小的缩略图 |
file |
Future<File?> |
获取原始文件 |
originBytes |
Future<Uint8List?> |
获取原始图像的二进制数据 |
latlngAsync() |
Future<LatLng?> |
获取位置信息(若有 GPS 信息) |