SwiftUI实现图片选择:添加图片按钮支持相册选图与拍照
在SwiftUI中实现相册选择/拍照功能的完整方案
实现思路
SwiftUI没有原生的图片选择/拍照组件,我们可以借助UIKit的PHPickerViewController(iOS14+,用于相册选择)和UIImagePickerController(用于拍照),通过UIViewControllerRepresentable把这些UIKit组件桥接到SwiftUI中使用。
完整修改后的代码
import SwiftUI import PhotosUI import UIKit struct ContentView: View { private enum Field: Int, CaseIterable { case cost, item, description } @State private var cost: String = "" @State private var item: String = "" @State private var description: String = "" @FocusState private var focusedField: Field? // 图片相关状态变量 @State private var selectedImage: UIImage? @State private var showImagePicker = false @State private var pickerType: PickerType = .photoLibrary // 标记选择器类型:相册/拍照 enum PickerType { case photoLibrary case camera } var body: some View { NavigationView { Form { TextField("Enter Amount ($)", text: $cost) .focused($focusedField, equals: .cost) .keyboardType(.decimalPad) TextField("What did you spent it on?", text: $item) .focused($focusedField, equals: .item) TextField("Description...",text: $description) .focused($focusedField, equals:.description) .frame(height: 100) // 图片预览与操作区域 Section { // 展示已选择的图片 if let image = selectedImage { Image(uiImage: image) .resizable() .scaledToFit() .frame(height: 200) } else { Text("No image selected") .foregroundColor(.gray) } // 相册选择/拍照按钮 HStack { Button("从相册选择") { pickerType = .photoLibrary showImagePicker = true } Button("拍照") { pickerType = .camera showImagePicker = true } } } header: { Text("添加图片") } } .toolbar { ToolbarItem(placement: .keyboard) { Button("Return") { focusedField = nil } } } // 弹出图片选择器 .fullScreenCover(isPresented: $showImagePicker) { if pickerType == .photoLibrary { PhotoPicker(selectedImage: $selectedImage) } else { CameraPicker(selectedImage: $selectedImage) } } } } } // 桥接PHPickerViewController,实现相册选择功能 struct PhotoPicker: UIViewControllerRepresentable { @Binding var selectedImage: UIImage? @Environment(\.dismiss) private var dismiss func makeUIViewController(context: Context) -> PHPickerViewController { var config = PHPickerConfiguration() config.filter = .images // 只允许选择图片 config.selectionLimit = 1 // 最多选1张 let picker = PHPickerViewController(configuration: config) picker.delegate = context.coordinator return picker } func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, PHPickerViewControllerDelegate { let parent: PhotoPicker init(_ parent: PhotoPicker) { self.parent = parent } func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { parent.dismiss() guard let result = results.first else { return } if result.itemProvider.canLoadObject(ofClass: UIImage.self) { result.itemProvider.loadObject(ofClass: UIImage.self) { image, _ in DispatchQueue.main.async { self.parent.selectedImage = image as? UIImage } } } } } } // 桥接UIImagePickerController,实现拍照功能 struct CameraPicker: UIViewControllerRepresentable { @Binding var selectedImage: UIImage? @Environment(\.dismiss) private var dismiss func makeUIViewController(context: Context) -> UIImagePickerController { let picker = UIImagePickerController() picker.sourceType = .camera picker.delegate = context.coordinator return picker } func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate { let parent: CameraPicker init(_ parent: CameraPicker) { self.parent = parent } func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { parent.dismiss() if let image = info[.originalImage] as? UIImage { parent.selectedImage = image } } func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { parent.dismiss() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
关键注意事项
- 权限配置:必须在
Info.plist中添加以下权限描述,否则App会崩溃:<key>NSPhotoLibraryUsageDescription</key> <string>需要访问您的相册以选择图片</string> <key>NSCameraUsageDescription</key> <string>需要访问您的相机以拍摄照片</string> - 版本兼容:如果要支持iOS13及以下版本,建议统一使用
UIImagePickerController处理相册和拍照(PHPickerViewController是iOS14+才支持的)。 - 优化建议:可以给已选择的图片添加删除按钮,方便用户替换;也可以对图片进行压缩处理,避免占用过多内存。
内容的提问来源于stack exchange,提问作者Alvin Lim
相关产品推荐
相关产品推荐

