如何在SwiftUI中打开ImagePicker?含UIImagePickerController实现疑问
在SwiftUI中实现图片选择器(基于UIImagePickerController)
嘿,我刚好在SwiftUI项目里折腾过这个,用UIImagePickerController完全可行——核心就是把UIKit的这个控制器用UIViewControllerRepresentable包装成SwiftUI能直接用的组件,下面给你一步步拆解:
第一步:包装UIImagePickerController成SwiftUI组件
我们需要写一个遵循UIViewControllerRepresentable的结构体,把UIImagePickerController的逻辑封装进去,同时通过Binding把选中的图片传递回SwiftUI视图:
import SwiftUI import UIKit struct ImagePicker: UIViewControllerRepresentable { // 绑定用于传递选中的图片 @Binding var selectedImage: UIImage? // 用Environment的dismiss来关闭picker @Environment(\.dismiss) private var dismiss // 选择来源:相册(photoLibrary)或相机(camera) let sourceType: UIImagePickerController.SourceType // 创建并配置UIImagePickerController实例 func makeUIViewController(context: Context) -> UIImagePickerController { let picker = UIImagePickerController() picker.sourceType = sourceType // 把Coordinator设为代理,处理选择/取消事件 picker.delegate = context.coordinator // 如果需要支持图片编辑,打开下面这行 // picker.allowsEditing = true return picker } // SwiftUI更新时的回调,这里不需要额外操作 func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {} // 创建Coordinator,用于处理UIKit的代理方法 func makeCoordinator() -> Coordinator { Coordinator(self) } // Coordinator类:实现UIImagePickerController的代理协议 class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate { let parent: ImagePicker init(_ parent: ImagePicker) { self.parent = parent } // 用户选中图片后的回调 func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { // 如果开启了编辑,就取editedImage,否则取originalImage let imageKey: UIImagePickerController.InfoKey = picker.allowsEditing ? .editedImage : .originalImage if let image = info[imageKey] as? UIImage { parent.selectedImage = image } // 关闭picker parent.dismiss() } // 用户取消选择的回调 func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { parent.dismiss() } } }
第二步:在SwiftUI视图中使用ImagePicker
现在你可以像用普通SwiftUI组件一样调用这个ImagePicker,通常用sheet来弹出它:
struct ContentView: View { @State private var selectedImage: UIImage? @State private var showImagePicker = false // 存储选择的来源类型(相册/相机) @State private var pickerSourceType: UIImagePickerController.SourceType = .photoLibrary var body: some View { VStack(spacing: 20) { // 展示选中的图片 if let image = selectedImage { Image(uiImage: image) .resizable() .scaledToFit() .frame(height: 300) .cornerRadius(12) } else { Text("还没选择图片哦") .font(.title2) .foregroundColor(.gray) .padding(.vertical, 100) } HStack(spacing: 16) { Button("从相册选择") { pickerSourceType = .photoLibrary showImagePicker = true } .buttonStyle(.borderedProminent) Button("拍照") { // 先检查相机是否可用(比如模拟器就没有相机) if UIImagePickerController.isSourceTypeAvailable(.camera) { pickerSourceType = .camera showImagePicker = true } else { // 这里可以弹个提示告诉用户相机不可用 print("当前设备没有可用相机") } } .buttonStyle(.borderedProminent) .tint(.green) } } .padding() // 弹出ImagePicker .sheet(isPresented: $showImagePicker) { ImagePicker(selectedImage: $selectedImage, sourceType: pickerSourceType) } } }
关键注意事项
- 权限配置:必须在
Info.plist中添加权限描述,否则App会直接崩溃:- 相册权限:添加
NSPhotoLibraryUsageDescription,值填类似“需要访问您的相册来选择图片”的描述 - 相机权限:添加
NSCameraUsageDescription,值填类似“需要访问您的相机来拍摄照片”的描述
- 相册权限:添加
- 相机可用性检查:调用相机前一定要用
UIImagePickerController.isSourceTypeAvailable(.camera)判断,避免在没有相机的设备上出错 - 图片编辑支持:如果需要让用户编辑图片,只要在创建picker时设置
picker.allowsEditing = true,然后从info[.editedImage]获取编辑后的图片就行
内容的提问来源于stack exchange,提问作者Shahar Melamed
相关产品推荐
相关产品推荐

