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() } } } } } }
修改后的完整代码
NavigationBar.swift
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
相关产品推荐
相关产品推荐

