1 Star 1 Fork 1

levi_plugin/flutter_wechat_assets_picker

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

Flutter WeChat Assets Picker

pub package pub package CodeFactor

Build status GitHub license GitHub stars GitHub forks

Awesome Flutter FlutterCandies

Language: English | 中文

基于 微信 UI 的 Flutter 图片选择器(同时支持视频和音频)。 该插件基于 photo_manager 实现资源相关功能, extended_image 用于查看图片, provider 用于协助管理选择器的状态。

当前的界面设计基于的微信版本:8.x 界面更新将在微信版本更新后随时进行跟进。

如果你需要拍照及录制视频,请先查看示例的详细用法, 并前往 wechat_camera_picker。 该插件是独立扩展,需要结合使用。

查看 迁移指南 了解如何从破坏性改动中迁移为可用代码。

目录列表

特性 ✨

  • ♻️ 支持基于代理重载的全量自定义
  • 🎏 完全可自定义的基于 ThemeData 的主题
  • 💚 复刻微信风格(甚至优化了更多的细节)
  • ⚡️ 根据配置调节的性能优化
  • 📷 图片资源支持
    • 🔬 HEIF 格式图片支持 (1)
  • 🎥 视频资源支持
  • 🎶 音频资源支持 (2)
  • 1️⃣ 单选模式模式
  • 💱 国际化 (i18n) 支持
    • ⏪ RTL 语言支持
  • ➕ 特殊 widget 构建支持
  • 🗂 自定义路径排序支持
  • 📝 自定义文本构建支持
  • ⏳ 自定义筛选规则支持
  • 💻 支持 MacOS

特别提醒 📝

  1. HEIF (HEIC) 图片支持获取和转换,但是它们的显示依托于 Flutter 的图片解析。 在此 issue 中 flutter/flutter#20522 有所说明。 若要用于显示,请使用 entity.fileAssetEntityImage 进行处理。
  2. 由于 iOS 和 macOS 的系统限制,在获取音频时只能获取应用沙盒环境内的音频

项目展柜 🖼️

name pub github
insta_assets_picker pub package star

截图 📸

1 2 3
4 5 6
7 8 9
10 10 12

开始前的注意事项 ‼️

在开始一切之前,请明确以下两点:

  • 由于理解差异和篇幅限制,并不是所有的内容都会明确地在文档中指出。 当你遇到没有找到需求和无法理解的概念时,请先运行项目的示例 example, 它可以解决 90% 的常见需求。
  • 该库与 photo_manager 有强关联性, 大部分方法的行为是由 photo_manager 进行控制的, 所以请尽可能地确保你了解以下两个类的概念:

当你有与相关的 API 和行为的疑问时,你可以查看 photo_manager API 文档 了解更多细节。

众多使用场景都已包含在示例中。 在你提出任何问题之前,请仔细并完整地查看和使用示例。

准备工作 🍭

版本兼容

2.10.0 3.0.0 3.3.0 3.7.0
8.4.0+
8.0.0+
7.3.0+
7.0.0+

如果在 flutter pub get 时遇到了 resolve conflict 失败问题, 请使用 dependency_overrides 解决。

Flutter

执行 flutter pub add wechat_assets_picker, 或者将 wechat_assets_picker 手动添加至 pubspec.yaml 引用。

dependencies:
  wechat_assets_picker: ^latest_version

最新的 稳定 版本是: pub package

最新的 开发 版本是: pub package

在你的代码中导入:

import 'package:wechat_assets_picker/wechat_assets_picker.dart';

Android

在使用这个 package 时,请确保 compileSdkVersiontargetSdkVersion 升级到 33。 否则,在 Android 13 设备上将有可能无法加载任何资源。

权限

Name 必需 已声明 最高 API 版本 其他
READ_EXTERNAL_STORAGE 32
WRITE_EXTERNAL_STORAGE 29
ACCESS_MEDIA_LOCATION 是* N/A 读取 EXIF 时必需
READ_MEDIA_IMAGES 是* N/A 读取图片时必需
READ_MEDIA_VIDEO 是* N/A 读取视频时必需
READ_MEDIA_AUDIO 是* N/A 读取音频时必需

如果你的目标 SDK 版本大于 33,且你不需要获取图片、视频或者音频, 你可以考虑只声明需要的权限,具体如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.your.app">
    <!--请求图片和视频权限-->
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
    <!--如果不需要获取音频,移除或者注释 READ_MEDIA_AUDIO-->
    <!--<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />-->
</manifest>

iOS

  1. ios/Podfile 中指定最低构建版本至 11.0
    platform :ios, '11.0'
    
  2. 将以下内容添加至 Info.plist
<key>NSAppTransportSecurity</key>
<dict>
	<key>NSAllowsArbitraryLoads</key>
	<true/>
</dict>
<key>NSPhotoLibraryUsageDescription</key>
<string>你的相册权限描述</string>

macOS

  1. macos/Podfile 中指定最低构建版本至 10.15
    platform :osx, '10.15'
    
  2. 使用 Xcode 打开 macos/Runner.xcworkspace。 接着将 macOS 的最低构建版本提升至 10.15
  3. iOS 一样,添加相同的内容到 Info.plist 里。

使用方法 📖

国际化

当你在选择资源的时候,package 会通过你的 BuildContext 读取 Locale?,返回对应语言的文字代理实现。 请确保你可以通过 BuildContext 获取到 Locale,否则将会 默认展示中文文字

内置的语言文字实现有:

  • 简体中文 (默认)
  • English
  • העברית
  • Deutsche
  • Локализация
  • 日本語
  • مة العربية
  • Délégué

如果你想使用自定义或固定的文字实现,请通过 AssetPickerConfig.textDelegate 传递调用。

简单的使用方法

final List<AssetEntity>? result = await AssetPicker.pickAssets(context);

你可以使用 AssetPickerConfig 来调整选择时的行为。

final List<AssetEntity>? result = await AssetPicker.pickAssets(
  context,
  pickerConfig: const AssetPickerConfig(),
);

AssetPickerConfig 的成员说明:

参数名 类型 描述 默认值
selectedAssets List<AssetEntity>? 已选的资源。确保不重复选择。 null
maxAssets int 最多选择的图片数量 9
pageSize int 分页加载时每页加载的资源数量。**必须为网格数的倍数。 80
gridThumbnailSize ThumbnailSize 预览网格的缩略图大小 ThumbnailSize.square(200)
pathThumbnailSize ThumbnailSize 路径选择器的缩略图大小 ThumbnailSize.square(80)
previewThumbnailSize ThumbnailSize? 预览时图片的缩略图大小 null
requestType RequestType 选择器选择资源的类型 RequestType.common
specialPickerType SpecialPickerType? 提供一些特殊的选择器类型以整合非常规的选择行为 null
keepScrollOffset bool 选择器是否可以从同样的位置开始选择 null
sortPathDelegate SortPathDelegate<AssetPathEntity>? 资源路径的排序实现,可自定义路径排序方法 CommonSortPathDelegate
sortPathsByModifiedDate bool 是否结合 FilterOptionGroup.containsPathModified 进行路径排序 false
filterOptions FilterOptionGroup? 允许用户自定义资源过滤条件 null
gridCount int 选择器网格数量 4
themeColor Color? 选择器的主题色 Color(0xff00bc56)
pickerTheme ThemeData? 选择器的主题提供,包括查看器 null
textDelegate AssetPickerTextDelegate? 选择器的文本代理构建,用于自定义文本 AssetPickerTextDelegate()
specialItemPosition SpecialItemPosition 允许用户在选择器中添加一个自定义item,并指定位置。 SpecialPosition.none
specialItemBuilder SpecialItemBuilder? 自定义item的构造方法 null
loadingIndicatorBuilder IndicatorBuilder? 加载器的实现 null
selectPredicate AssetSelectPredicate 判断资源可否被选择 null
shouldRevertGrid bool? 判断资源网格是否需要倒序排列 null
limitedPermissionOverlayPredicate LimitedPermissionOverlayPredicate? 判断有限的权限情况下是否展示提示页面 null
pathNameBuilder PathNameBuilder<AssetPathEntity>? 基于路径(相册)构建自定义名称的方法 null
  • maxAssets 等于 1(即单选模式),搭配 SpecialPickerType.noPreview 使用会在用户点选资源换时立刻选中并返回。
  • requestTypeRequestType.video 时, iOS 获取的资源会包括 实况图片 (Live Photos)。 你可以设置 FilterOptionGroup.containsLivePhotosfalse 来禁用。
  • limitedPermissionOverlayPredicate 不是持久化的, 如果你需要在应用下次启动时不再显示权限受限的页面,请自主实现持久化的控制。

更详细的使用方法

我们已将常用的调用方法封装在 example 中。 你可以在 example/lib/pages/multi_assets_page.dartexample/lib/pages/single_assets_page.dart 找到 List<PickMethod> pickMethods, 它分别定义了多选和单选可用的选择模式。 在选择资源后,资源会暂存并展示在页面下方。

展示选中的资源

AssetEntityImageAssetEntityImageProvider 可以为 图片 & 视频 展示缩略图,以及展示 图片的原图。 它的使用方法与常见的 ImageImageProvider 一致。

AssetEntityImage(asset, isOriginal: false);

或:

/// AssetEntityImageProvider
Image(image: AssetEntityImageProvider(asset, isOriginal: false));

注册资源变化回调

/// 注册回调
AssetPicker.registerObserve();

/// 取消注册回调
AssetPicker.unregisterObserve();

在表单数据中上传 AssetEntity

AssetEntity 包含有多种 I/O 相关的方法可以用于上传。 请注意,I/O 相关的方法会消耗性能(通常是时间和内存),它们不应该被频繁调用。

使用 http

http package: https://pub.flutter-io.cn/packages/http

http package 使用v MultipartFile 来在请求中处理文件。

示例代码如下:

import 'package:http/http.dart' as http;

Future<void> upload() async {
  final entity = await obtainYourEntity();
  final uri = Uri.https('example.com', 'create');
  final request = http.MultipartRequest('POST', uri)
    ..fields['test_field'] = 'test_value'
    ..files.add(await multipartFileFromAssetEntity(entity));
  final response = await request.send();
  if (response.statusCode == 200) {
    print('Uploaded!');
  }
}

Future<http.MultipartFile> multipartFileFromAssetEntity(AssetEntity entity) async {
  http.MultipartFile mf;
  // Using the file path.
  final file = await entity.file;
  if (file == null) {
    throw StateError('Unable to obtain file of the entity ${entity.id}.');
  }
  mf = await http.MultipartFile.fromPath('test_file', file.path);
  // Using the bytes.
  final bytes = await entity.originBytes;
  if (bytes == null) {
    throw StateError('Unable to obtain bytes of the entity ${entity.id}.');
  }
  mf = http.MultipartFile.fromBytes('test_file', bytes);
  return mf;
}
使用 diox

diox package: https://pub.flutter-io.cn/packages/diox

diox package 同样使用了 MultipartFile 来在请求中处理文件。

示例代码:

import 'package:diox/diox.dart' as diox;

Future<void> upload() async {
  final entity = await obtainYourEntity();
  final uri = Uri.https('example.com', 'create');
  final response = diox.Dio().requestUri(
    uri,
    data: diox.FormData.fromMap({
      'test_field': 'test_value',
      'test_file': await multipartFileFromAssetEntity(entity),
    }),
  );
  print('Uploaded!');
}

Future<diox.MultipartFile> multipartFileFromAssetEntity(AssetEntity entity) async {
  diox.MultipartFile mf;
  // Using the file path.
  final file = await entity.file;
  if (file == null) {
    throw StateError('Unable to obtain file of the entity ${entity.id}.');
  }
  mf = await diox.MultipartFile.fromFile(file.path);
  // Using the bytes.
  final bytes = await entity.originBytes;
  if (bytes == null) {
    throw StateError('Unable to obtain bytes of the entity ${entity.id}.');
  }
  mf = diox.MultipartFile.fromBytes(bytes);
  return mf;
}

自定义选择器

AssetPickerBuilderDelegateAssetPickerViewerBuilderDelegateAssetPickerProviderAssetPickerViewerProvider 均已暴露且可重载。 使用者可以使用自定义的泛型类型 <A: 资源, P: 路径>, 配合继承与重载,实现对应抽象类和类中的方法。 更多用法请查看示例中的 Custom 页面, 该页面包含一个以 <File, Directory> 为类型基础的选择器。

你可以在「Custom」页面尝试自定义的选择器。 目前我们提供了一个基于 DirectoryFile (与 photo_manager 完全无关)实现的选择器, 以及一个多 Tab 页切换的选择器。 如果你觉得你的实现有价值或能帮助到其他人,欢迎以 PR 的形式进行提交。 更多细节请阅读 贡献自定义实现

常见问题 ❔

Execution failed for task ':photo_manager:compileDebugKotlin'

查看 photo_manager#561 了解详细的解决方法。

FileUint8List 创建 AssetEntity 的方法

如果需要使用此库结合一些拍照需求, 可通过以下方法将 FileUint8List 转为 AssetEntity

final File file = your_file; // 你的 File 对象
final String path = file.path;
final AssetEntity fileEntity = await PhotoManager.editor.saveImageWithPath(
  path,
  title: basename(path),
); // 存入手机并生成 AssetEntity

final Uint8List data = your_data; // 你的 Uint8List 对象
final AssetEntity imageEntity = await PhotoManager.editor.saveImage(
  file.path,
  title: '带有后缀的名称.jpg',
); // 存入手机并生成 AssetEntity

注意:如果不想保留文件,请尽量用 File 承载中间操作, 否则在调用 AssetEntity 的删除时,系统可能会触发弹窗:

final List<String> result = await PhotoManager.editor.deleteWithIds(
  <String>[entity.id],
);

你可以阅读 photo_manager#from-raw-dataphoto_manager#delete-entities 了解更多细节。

控制台提示 'Failed to find GeneratedAppGlideModule'

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 通过注解来保证单例,防止单例或版本之间的冲突, 而因为 photo_manager 使用了 Glide 提供部分图片功能, 所以使用它的项目必须实现自己的 AppGlideModule。 请移步 Glide Generated API 文档 了解如何实现。

致谢

IntelliJ IDEA 的每个方面都旨在最大化开发者生产力。结合智能编码辅助与符合人体工程学的设计,让开发不仅高效,更成为一种享受。

感谢 JetBrains 为开源项目提供免费的 IntelliJ IDEA 等 IDE 的授权。

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [2019] [FlutterCandies] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

简介

微信相册插件,增加编辑按钮和确认按钮 展开 收起
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Dart
1
https://gitee.com/plugin_levi/flutter_wechat_assets_picker.git
git@gitee.com:plugin_levi/flutter_wechat_assets_picker.git
plugin_levi
flutter_wechat_assets_picker
flutter_wechat_assets_picker
master

搜索帮助