SwiftUI中关闭UIKit视图并返回原生SwiftUI视图传UIImage问题
在SwiftUI中集成UIKit SDK后跳转SwiftUI视图出现嵌套叠加问题的解决
我在SwiftUI项目中集成了基于UIKit编写的Pixel SDK,已通过UIViewControllerRepresentable封装展示SDK视图,但从SDK回调跳转到SwiftUI视图并传递UIImage时,使用UIHostingController包裹ExportView后,后续通过NavigationLink跳转的SwiftUI视图会嵌套在同一个UIHostingController内部,出现视图叠加、多次操作后占满屏幕的问题,需要回到原生SwiftUI视图体系解决此问题。
相关代码
1. SDK代理与UIViewControllerRepresentable封装
class editorDelegate : imgExported, EditControllerDelegate { func editController(_ editController: EditController, didLoadEditing session: Session) { // Called after the EditController's view did load. } func editController(_ editController: EditController, didFinishEditing session: Session) { if let image = session.image { ImageExporter.shared.export(image: image, completion: { (error, uiImage) in if let error = error { print("Unable to export image: \(error)") return } let exportView = UIHostingController(rootView: ExportView(imgText: .constant(image.exportedImageURL.absoluteString), uimage: .constant(uiImage!)).environmentObject(imgExported())) editController.navigationController?.pushViewController(exportView, animated: true) session.destroy() }) } } func editController(_ editController: EditController, didCancelEditing session: Session?) { // Called when the back button in the EditController is pressed. } } let deLegate = editorDelegate() let container = ContainerController() struct showFullEditor: UIViewControllerRepresentable { typealias UIViewControllerType = UINavigationController var controllers: [UIViewController] = [] func makeUIViewController(context: Context) -> UIViewControllerType { container.editControllerDelegate = deLegate let sFullEditor = UINavigationController(rootViewController: container) sFullEditor.modalPresentationStyle = .automatic return sFullEditor } func updateUIViewController(_ uiViewController: UINavigationController, context: Self.Context) { } }
2. ExportView SwiftUI视图
struct ExportView: View { @Binding var imgText: String @Binding var uimage: UIImage var body: some View { NavigationView{ VStack { Image(uiImage: uimage).resizable().aspectRatio(contentMode: .fit) HStack { NavigationLink(destination: MainMenuView()){ Text("Guardar") }.simultaneousGesture(TapGesture().onEnded(){ UIImageWriteToSavedPhotosAlbum(uimage, nil, nil, nil) }) NavigationLink(destination: MakeUpView()){ Text("Make Up") } NavigationLink(destination: FullEditorView()){ Text("Borrar") } } }.navigationTitle("Exported View") }.navigationViewStyle(.stack) } } struct ExportView_Previews: PreviewProvider { static var previews: some View { ExportView(imgText: .constant("Test"), uimage: .constant(UIImage())) } }
解决方案
问题核心是:将SwiftUI视图嵌套在UIKit导航栈后,SwiftUI内部的NavigationLink会在当前UIHostingController容器内跳转,而非使用SwiftUI原生导航体系。推荐采用以下方式解决:
方式一:从UIKit导航栈切回SwiftUI原生导航栈
通过模态展示SDK视图,完成后关闭SDK视图,回到SwiftUI导航栈中展示ExportView,让后续跳转都在原生SwiftUI体系内进行。
- 修改SwiftUI主入口视图,添加状态变量控制SDK视图显示和接收导出图片:
struct MainContentView: View { @State private var showSDKEditor = false @State private var exportedImage: UIImage? = nil var body: some View { NavigationStack { Button("打开SDK编辑器") { showSDKEditor = true } // 接收图片后展示ExportView .fullScreenCover(item: $exportedImage) { image in ExportView(imgText: .constant(""), uimage: .constant(image)) } // 模态展示SDK的UIKit视图 .fullScreenCover(isPresented: $showSDKEditor) { showFullEditor(onImageExported: { image in exportedImage = image showSDKEditor = false // 关闭SDK视图 }) } } } }
- 更新
showFullEditor,添加回调闭包传递导出图片:
struct showFullEditor: UIViewControllerRepresentable { typealias UIViewControllerType = UINavigationController let onImageExported: (UIImage) -> Void // 新增回调闭包 func makeUIViewController(context: Context) -> UIViewControllerType { // 初始化代理时传入回调 let delegate = editorDelegate(onImageExported: onImageExported) container.editControllerDelegate = delegate let sFullEditor = UINavigationController(rootViewController: container) sFullEditor.modalPresentationStyle = .automatic return sFullEditor } func updateUIViewController(_ uiViewController: UINavigationController, context: Self.Context) {} }
- 修改
editorDelegate,移除UIHostingController跳转逻辑,改用回调传递图片并关闭SDK视图:
class editorDelegate : imgExported, EditControllerDelegate { private let onImageExported: (UIImage) -> Void // 通过初始化方法传入回调 init(onImageExported: @escaping (UIImage) -> Void) { self.onImageExported = onImageExported } func editController(_ editController: EditController, didLoadEditing session: Session) {} func editController(_ editController: EditController, didFinishEditing session: Session) { if let image = session.image { ImageExporter.shared.export(image: image, completion: { (error, uiImage) in if let error = error { print("Unable to export image: \(error)") return } guard let uiImage = uiImage else { return } // 调用回调传递图片回SwiftUI self.onImageExported(uiImage) // 关闭SDK视图 editController.dismiss(animated: true) { session.destroy() } }) } } func editController(_ editController: EditController, didCancelEditing session: Session?) { editController.dismiss(animated: true) session?.destroy() } }
这种方式彻底分离了UIKit SDK视图和SwiftUI原生视图的导航体系,从根源上解决了嵌套叠加问题。
内容的提问来源于stack exchange,提问作者KBDevs
相关产品推荐
相关产品推荐

