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

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体系内进行。

  1. 修改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视图
                })
            }
        }
    }
}
  1. 更新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) {}
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 15:27:20