You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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()
    }
}

关键注意事项

  1. 权限配置:必须在Info.plist中添加以下权限描述,否则App会崩溃:
    <key>NSPhotoLibraryUsageDescription</key>
    <string>需要访问您的相册以选择图片</string>
    <key>NSCameraUsageDescription</key>
    <string>需要访问您的相机以拍摄照片</string>
    
  2. 版本兼容:如果要支持iOS13及以下版本,建议统一使用UIImagePickerController处理相册和拍照(PHPickerViewController是iOS14+才支持的)。
  3. 优化建议:可以给已选择的图片添加删除按钮,方便用户替换;也可以对图片进行压缩处理,避免占用过多内存。

内容的提问来源于stack exchange,提问作者Alvin Lim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 11:15:59