👨🏻‍💻's 博客

慢品人间烟火色,闲观万事岁月长

0%

Flutter - 原生交互 - 相册

环境

Flutter 3.29

macOS Sequoia 15.4.1

Xcode 16.3

iOS 13.4.1
iOS 18.5

集成image_picker

在Flutter中可以使用image_picker插件实现从相册中获取图片

添加插件

flutter中访问相册image_picker插件

1
2
¥ flutter pub add image_picker
¥ flutter pub get

Xcode工程的GeneratePluginRegistrant新增了对应的注册代码

1
2
3
4
5
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
...
[FLTImagePickerPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTImagePickerPlugin"]];
...
}

更新Xcode的pod依赖

1
¥ pod update
1.png

添加权限

1
2
3
4
5
6
7
8
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问相册以选择图片</string>

<!-- image_picker也支持直接拍照 -->
<key>NSCameraUsageDescription</key>
<string>需要访问相机用于拍照</string>
<key>NSMicrophoneUsageDescription</key>
<string>需要访问麦克风用于拍摄视频</string>

获取单张照片

可以使用ImagePicker().pickerImage()获取单张图片

1
2
3
else if (index == 2) {
_pickImage(ImageSource.gallery),
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Future<void> _pickImage(ImageSource source) async {
try {
// source值可以是相机(camera)或相册(gallery)
final pickedFile = await ImagePicker().pickImage(source: source);

if (pickedFile != null) {
setState(() {
if (mounted) {
// pop弹窗并返回从相册中选择的图片
Navigator.pop(context, File(pickedFile.path));
}
});
}
} catch (e) {
debugPrint("图片选择错误: $e");
}
}

在上一个界面接收从相册中选择的图片并刷新界面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 floatingActionButton: FloatingActionButton(
onPressed: () async {
final result = await menuWidget(context: context);
if (result != null) {
setState(() {
_defaultCover = result;
});
}
},

backgroundColor: Colors.orangeAccent,
child: const Icon(Icons.add, color: Colors.white),
),

Future menuWidget({required BuildContext context}) async {
return Navigator.push(
context,
PageRouteBuilder(
opaque: false,
barrierColor: Colors.black.withValues(alpha: 0.2),
pageBuilder:
(context, animation, secondaryAnimation) =>
PopScope(canPop: true, child: MenuWidget()),
transitionsBuilder:
(context, animation, secondaryAnimation, child) => SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, 2.4),
end: Offset.zero,
).animate(animation),
child: SlideTransition(
position: Tween<Offset>(
begin: Offset.zero,
end: const Offset(0.0, 2.4),
).animate(secondaryAnimation),
child: child,
),
),
),
);
}

iOS

RPReplay_Final1750762491.mov_optimized.gif

Andorid

42_1750841362.mp4_optimized.gif

获取多张照片

可以使用ImagePicker().pickMultiImage()获取多张图片

1
_pickMultiImage(),
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Future<void> _pickMultiImage() async {
try {
// 设置最多获取9张图片
final pickedFiles = await ImagePicker().pickMultiImage(limit: 9);
if (pickedFiles.isNotEmpty) {
setState(() {
if (mounted) {
Navigator.pop(context, pickedFiles);
}
});
}
} catch (e) {
debugPrint("图片选择错误: $e");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
floatingActionButton: FloatingActionButton(
onPressed: () async {
final result = await menuWidget(context: context);
if (result != null) {
setState(() {
if (result is XFile) {
_defaultCover = result;
/// 选择多张照片
} else if (result is List<XFile>) {
_defaultCover = result[0];
}
});
}
},

backgroundColor: Colors.orangeAccent,
child: const Icon(Icons.add, color: Colors.white),
),

选择多张照片在iOS平台上只在14+才生效,用的是PhotosUI.framework中的PHPicker,因为手上测试机是13.4.1设备一直无法多选图片,查看源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- (void)pickMultiImageWithMaxSize:(nonnull FLTMaxSize *)maxSize
quality:(nullable NSNumber *)imageQuality
fullMetadata:(BOOL)fullMetadata
limit:(nullable NSNumber *)limit
completion:(nonnull void (^)(NSArray<NSString *> *_Nullable,
FlutterError *_Nullable))completion {
[self cancelInProgressCall];
FLTImagePickerMethodCallContext *context =
[[FLTImagePickerMethodCallContext alloc] initWithResult:completion];
context.maxSize = maxSize;
context.imageQuality = imageQuality;
context.requestFullMetadata = fullMetadata;
context.maxImageCount = limit.intValue;

if (@available(iOS 14, *)) {
[self launchPHPickerWithContext:context];
} else {
// Camera is ignored for gallery mode, so the value here is arbitrary.
[self launchUIImagePickerWithSource:[FLTSourceSpecification makeWithType:FLTSourceTypeGallery
camera:FLTSourceCameraRear]
context:context];
}
}
17504193664484.jpg

limit值传了9,但是launchUIImagePickerWithSource:context:中没有对limit做任何处理代码

1
2
3
4
5
6
- (void)launchUIImagePickerWithSource:(nonnull FLTSourceSpecification *)source
context:(nonnull FLTImagePickerMethodCallContext *)context {
UIImagePickerController *imagePickerController = [self createImagePickerController];
imagePickerController.modalPresentationStyle = UIModalPresentationCurrentContext;
imagePickerController.delegate = self;
...
ScreenRecording_06-25-2025.mov_optimized.gif

获取视频

使用ImagePicker().pickMedia()可以从相册获取视频文件

1
2
3
4
5
6
7
8
9
10
11
12
Future<void> _pickVideo() async {
try {
final pickedVideo = await ImagePicker().pickMedia();
if (pickedVideo != null) {
setState(() {

});
}
} catch (e) {
debugPrint("图片选择错误: $e");
}
}
Snip20250625_1.png

获取多媒体文件

使用ImagePicker().pickMultipleMedia()可以从相册获取视频和照片

1
2
3
4
5
6
7
8
9
10
11
Future<void> _pickMultiMedia() async {
try {
final pickedMedia = await ImagePicker().pickMultipleMedia();
setState(() {
// 页面刷新
Navigator.pop(context, pickedMedia);
});
} catch (e) {
debugPrint("图片选择错误: $e");
}
}

参考

  1. Image Picker plugin for Flutter