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

SwiftUI中如何将ImagePicker选中的图片传递到其他视图?

解决图库选图无法绑定到UploadPostView的问题

你当前的问题出在两个核心点:

  • 从图库选图后,ImagePicker的uiImage没有同步到capturedImage绑定变量,导致UploadPostView无法获取到图库选择的图片
  • UploadPostView内部新建了独立的ImagePicker实例,和CustomCameraView里的不是同一个,自然拿不到选图结果

以下是具体修复步骤:

第一步:修改CustomCameraView,同步图库选图到capturedImage

在CustomCameraView中添加对imagePicker.$uiImage的监听,当图库选图完成后自动更新capturedImage:

import SwiftUI
import PhotosUI

struct CustomCameraView: View {
    let cameraService = CameraService()
    @Environment(\.dismiss) private var dismiss
    @StateObject var imagePicker = ImagePicker()
    @Binding var capturedImage: UIImage?

    var body: some View {
        
        // 照片已拍摄或已选择时进入编辑页
        if (imagePicker.image != nil) || (capturedImage != nil) {
            UploadPostView(capturedImage: $capturedImage)
        }
        
        // 未选择/拍摄照片时显示相机界面
        else {
            ZStack (alignment: .topLeading) {
                
                CameraView(cameraService: cameraService) { result in
                    switch result {
                    case .success(let photo):
                        if let data = photo.fileDataRepresentation() {
                            capturedImage = UIImage(data: data)
                        } else {
                            print("Error: no image data found")
                        }
                    case .failure(let err):
                        print(err.localizedDescription)
                    }
                }
                VStack (alignment: .leading) {
                    Button {
                        dismiss()
                    } label: {
                        Image("xmark")
                            .renderingMode(.template)
                            .resizable()
                            .frame(width: 28, height: 28)
                            .foregroundColor(.white)
                    }
                    
                    .padding()
                    Spacer()
                    
                    HStack {
                        PhotosPicker(selection: $imagePicker.imageSelection) {
                            Image("image-square")
                                .renderingMode(.template)
                                .resizable()
                                .frame(width: 32, height: 28)
                                .foregroundColor(.white)
                        }
                        Spacer()
                        Button {
                            cameraService.capturePhoto()
                        } label: {
                            Image(systemName: "circle")
                                .font(.system(size: 72))
                                .foregroundColor(.white)
                        }
                        Spacer()
                        Rectangle()
                            .foregroundColor(.clear)
                            .frame(width: 32, height: 28)
                    }
                    .padding()
                }
            }
            .cornerRadius(6)
            .background(.black)
            // 新增监听:图库选图完成后同步到capturedImage
            .onChange(of: imagePicker.uiImage) { newImage in
                if let newImage = newImage {
                    capturedImage = newImage
                }
            }
        }
    }
}

第二步:简化UploadPostView,移除冗余的ImagePicker

UploadPostView不需要单独创建ImagePicker,直接使用绑定的capturedImage即可,统一图片显示和上传逻辑:

import SwiftUI
import Kingfisher
import PhotosUI

struct UploadPostView: View {
    @Environment(\.dismiss) private var dismiss
    @ObservedObject var viewModel = UploadPostViewModel()
    @State var caption = ""
    @State var rating = 0
    @Binding var capturedImage: UIImage?
    
    var body: some View {
            VStack {
                // 统一显示capturedImage(拍摄或图库选择的图片)
                if let image = capturedImage {
                    Image(uiImage: image)
                        .resizable()
                        .aspectRatio(contentMode: .fill)
                        .frame(minWidth: 100, maxWidth: .infinity, minHeight: 100, maxHeight: .infinity)
                        .cornerRadius(6)
                        .clipped()
                }
            
                HStack {
                    Spacer()
                    Button {
                        if let uiimage = capturedImage {
                            viewModel.uploadPost(caption: caption, image: uiimage, rating: rating)
                            viewModel.loading = true
                        }
                    } label: {
                        if viewModel.loading {
                            ProgressView()
                                .progressViewStyle(CircularProgressViewStyle(tint: .white))
                                .frame(width: 24, height: 24)
                                .padding()
                                .background(Color.accentColor)
                                .foregroundColor(.white)
                                .clipShape(Circle())
                        } else {
                            Image("send-fill")
                                .renderingMode(.template)
                                .resizable()
                                .frame(width: 24, height: 24)
                                .padding()
                                .background(Color.accentColor)
                                .foregroundColor(.white)
                                .clipShape(Circle())
                        }
                    }
                }.padding(8)
            }
        .background(.black)
        .onReceive(viewModel.$didUploadPost) { success in
            if success {
                dismiss()
            }
        }
        
    }
}

可选优化:让ImagePicker直接支持外部绑定(更内聚的写法)

如果后续需要复用ImagePicker,可以修改它直接接收外部绑定变量,省去额外的监听逻辑:

import SwiftUI
import PhotosUI

@MainActor
class ImagePicker: ObservableObject {
    
    @Published var image: Image?
    @Published var uiImage: UIImage?
    // 新增外部绑定变量
    @Binding var externalImage: UIImage?
    
    // 修改初始化方法,接收绑定参数
    init(externalImage: Binding<UIImage?>) {
        self._externalImage = externalImage
    }

    @Published var imageSelection: PhotosPickerItem? {
        didSet {
            if let imageSelection {
                Task {
                    try await loadTransferable(from: imageSelection)
                }
            }
        }
    }
    
    func loadTransferable(from imageSelection: PhotosPickerItem?) async throws {
        do {
            if let data = try await imageSelection?.loadTransferable(type: Data.self) {
                if let uiImage = UIImage(data: data) {
                    self.uiImage = uiImage
                    self.image = Image(uiImage: uiImage)
                    // 直接同步到外部绑定变量
                    self.externalImage = uiImage
                }
            }
        } catch {
            print(error.localizedDescription)
            image = nil
            externalImage = nil
        }
    }
}

使用时,在CustomCameraView中初始化ImagePicker:

struct CustomCameraView: View {
    let cameraService = CameraService()
    @Environment(\.dismiss) private var dismiss
    @StateObject var imagePicker: ImagePicker
    @Binding var capturedImage: UIImage?

    // 自定义初始化方法
    init(capturedImage: Binding<UIImage?>) {
        self._capturedImage = capturedImage
        self._imagePicker = StateObject(wrappedValue: ImagePicker(externalImage: capturedImage))
    }

    // ... 其余代码保持不变,可移除之前添加的onChange监听
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 18:39:58