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

SwiftUI中如何以非Sheet形式展示UIViewControllerRepresentable?

如何通过NavigationLink或嵌入视图展示UIViewControllerRepresentable(如VNDocumentCameraViewController)

问题描述

现有大量教程讲解如何以Sheet形式展示UIViewControllerRepresentable(例如VNDocumentCameraViewController),但我想了解能否通过NavigationLink或直接嵌入其他视图的方式将其作为常规视图展示。

当前使用代码:

NavigationLink("Add with camera", destination: ScannerView(completion: {result in  resultHandler(text: result)}))

遇到的问题:

  • 视图嵌入到标签导航视图中而非全屏显示
  • Save按钮对应的completion回调无法正常工作
  • 直接嵌入其他视图时,Xcode提示“Initializer is never used”错误,视图无法显示

解决方案

一、让NavigationLink跳转的视图全屏显示

要让UIViewControllerRepresentable全屏展示,需在ScannerView内部给包裹的视图控制器设置modalPresentationStyle为.fullScreen,同时可配合隐藏导航栏优化显示效果。

修改ScannerView的实现:

struct ScannerView: UIViewControllerRepresentable {
    // 用@escaping标记闭包,确保能正确传递回调
    var completion: @escaping (String) -> Void
    
    func makeUIViewController(context: Context) -> VNDocumentCameraViewController {
        let scanner = VNDocumentCameraViewController()
        scanner.delegate = context.coordinator
        // 设置全屏展示样式
        scanner.modalPresentationStyle = .fullScreen
        return scanner
    }
    
    func updateUIViewController(_ uiViewController: VNDocumentCameraViewController, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator(completion: completion)
    }
    
    class Coordinator: NSObject, VNDocumentCameraViewControllerDelegate {
        var completion: (String) -> Void
        
        init(completion: @escaping (String) -> Void) {
            self.completion = completion
        }
        
        func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
            // 处理扫描结果,提取文本(示例逻辑,需替换为实际OCR处理)
            var scannedText = ""
            for pageIndex in 0..<scan.pageCount {
                let image = scan.imageOfPage(at: pageIndex)
                // 此处添加OCR转换文本的逻辑
                // scannedText += 转换后的文本内容
            }
            // 触发回调
            completion(scannedText)
            // 关闭扫描视图控制器
            controller.dismiss(animated: true)
        }
        
        func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) {
            controller.dismiss(animated: true)
        }
    }
}

同时在NavigationLink中隐藏导航栏:

NavigationLink("Add with camera", destination: ScannerView(completion: { result in
    resultHandler(text: result)
}).navigationBarHidden(true))

二、修复completion回调不工作的问题

回调失效通常是因为闭包未标记@escaping,或未在扫描完成后正确触发回调并关闭视图。上述ScannerView实现中,已确保:

  • 闭包参数标记@escaping
  • 在didFinishWith方法中先调用completion传递结果,再手动调用controller.dismiss关闭视图

三、直接嵌入视图的解决方案

直接嵌入时出现初始化器未使用的错误,多是因为视图未被赋予足够的布局空间,或ScannerView实现有疏漏。

可将ScannerView放入填充全屏的容器中:

struct ContentView: View {
    var body: some View {
        VStack {
            Text("扫描区域")
            ScannerView(completion: { result in
                print("扫描结果:\(result)")
            })
            // 让扫描视图填充剩余空间
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
    }
}

同时检查ScannerView的初始化器是否正确,确保completion参数类型为@escaping (String) -> Void,无拼写错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 12:35:18