SwiftUI中如何以非Sheet形式展示UIViewControllerRepresentable?
问题描述
现有大量教程讲解如何以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
相关产品推荐
相关产品推荐

