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

SwiftUI中如何在视图间传递图片值?现有代码问题求助

解决SwiftUI中ImagePicker选图后跳转至新视图展示图片的问题

问题根源

你当前的代码中,在sheet的onDismiss闭包里直接创建newPostView实例是无效的——SwiftUI是声明式UI框架,视图的展示必须通过状态变量驱动,而非在闭包中直接实例化视图。

修改方案

步骤1:添加控制新视图展示的状态变量

在NavigationBar结构体中添加一个@State变量,用于控制newPostView的显示:

@State var showNewPostView = false

步骤2:修改ImagePicker的onDismiss逻辑

将原来的onDismiss闭包改为:当选中图片后,触发新视图的展示:

.sheet(isPresented: $imagePickerPresented, onDismiss: {
    // 只有选中图片后才打开新视图
    if selectedImage != nil {
        showNewPostView = true
    }
}) {
    ImagePicker(image: $selectedImage)
}

步骤3:添加新视图的展示逻辑

在NavigationBar的body末尾(ZStack之后)添加新视图的fullScreenCover(也可根据需求换成sheet):

.fullScreenCover(isPresented: $showNewPostView) {
    newPostView(image: $selectedImage)
}

步骤4:更新newPostView以展示图片

修改newPostView,让它能接收并展示选中的图片:

struct newPostView: View {
    @Binding var image: UIImage?
    @Environment(\.dismiss) var dismiss
    
    var body: some View {
        NavigationStack {
            VStack {
                if let image = image {
                    Image(uiImage: image)
                        .resizable()
                        .scaledToFit()
                        .padding()
                } else {
                    Text("未选择图片")
                }
                
                Spacer()
            }
            .navigationTitle("发布新帖")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("返回") {
                        dismiss()
                    }
                }
            }
        }
    }
}

修改后的完整代码

import SwiftUI

struct NavigationBar: View {
    var title = ""
    @Binding var hasScrolled: Bool
    @State var imagePickerPresented = false
    @State private var selectedImage: UIImage?
    @State var showNewPostView = false // 新增状态变量
    @State var captionText = ""
    
    var body: some View {
        ZStack {
            Color.clear
                .background(.ultraThinMaterial)
                .blur(radius: 10)
                .opacity(hasScrolled ? 1 : 0)
            
            Text(title)
                .animatableFont(size: hasScrolled ? 22 : 34, weight: .bold)
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding(.leading, 20)
                .padding(.top, 20)
                .offset(y: hasScrolled ? -4 : 0)
            
            HStack(spacing: 16) {
                Button {
                    imagePickerPresented = true
                } label: {
                    Image(systemName: "plus.square")
                        .font(.title3.weight(.bold))
                        .frame(width: 46, height: 46)
                        .foregroundColor(.secondary)
                        .background(.ultraThinMaterial, in: RoundedRectangle(cornerRadius: 14, style: .continuous))
                        .strokeStyle(cornerRadius: 14)
                }
                .sheet(isPresented: $imagePickerPresented, onDismiss: {
                    // 选中图片后打开新视图
                    if selectedImage != nil {
                        showNewPostView = true
                    }
                }) {
                    ImagePicker(image: $selectedImage)
                }
            }
            .frame(maxWidth: .infinity, alignment: .trailing)
            .padding(.trailing, 20)
            .padding(.top, 20)
            .offset(y: hasScrolled ? -4 : 0)
        }
        .frame(height: hasScrolled ? 44 : 70)
        .frame(maxHeight: .infinity, alignment: .top)
        // 新增:展示新视图
        .fullScreenCover(isPresented: $showNewPostView) {
            newPostView(image: $selectedImage)
        }
    }
}

newPostView.swift

import SwiftUI

struct newPostView: View {
    @Binding var image: UIImage?
    @Environment(\.dismiss) var dismiss
    
    var body: some View {
        NavigationStack {
            VStack {
                if let image = image {
                    Image(uiImage: image)
                        .resizable()
                        .scaledToFit()
                        .padding()
                } else {
                    Text("未选择图片")
                }
                
                Spacer()
            }
            .navigationTitle("发布新帖")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button("返回") {
                        dismiss()
                    }
                }
            }
        }
    }
}

ImagePicker.swift(无需修改)

import SwiftUI

struct ImagePicker: UIViewControllerRepresentable {
    @Binding var image: UIImage?
    @Environment(\.presentationMode) var mode
    
    func makeUIViewController(context: Context) -> some UIViewController {
        let picker = UIImagePickerController()
        picker.delegate = context.coordinator
        return picker
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        
    }
    
    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
        let parent: ImagePicker
        
        init(_ parent: ImagePicker) {
            self.parent = parent
        }
        
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            guard let image = info[.originalImage] as? UIImage else { return }
            self.parent.image = image
            self.parent.mode.wrappedValue.dismiss()
        }
    }
}

说明

  • 使用fullScreenCover而非sheet可以提供更沉浸式的发布体验,也可以根据需求换回sheet
  • 新增了返回按钮和导航栏,提升用户体验
  • 只有当用户确实选中图片后,才会触发新视图的展示,避免空视图的情况

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 18:18:28