ios - 在 Xcode 11、SwiftUI 中呈现 UIViewController 的问题
问题描述
我有一个嵌入在 UIViewController 中的 QR 码扫描仪。我一直在查看其他帖子和博客,但它们都是单页应用程序,它们在应用程序启动时将 UIViewController 作为主要应用程序。我只需要它在按钮操作中打开,由于某种原因我无法正确显示扫描仪?
这是QR扫描仪代码:
class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
var captureSession: AVCaptureSession!
var previewLayer: AVCaptureVideoPreviewLayer!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.black
captureSession = AVCaptureSession()
guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return }
let videoInput: AVCaptureDeviceInput
do {
videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
} catch {
return
}
if (captureSession.canAddInput(videoInput)) {
captureSession.addInput(videoInput)
} else {
failed()
return
}
let metadataOutput = AVCaptureMetadataOutput()
if (captureSession.canAddOutput(metadataOutput)) {
captureSession.addOutput(metadataOutput)
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
metadataOutput.metadataObjectTypes = [.qr]
} else {
failed()
return
}
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.frame = view.layer.bounds
previewLayer.videoGravity = .resizeAspectFill
view.layer.addSublayer(previewLayer)
captureSession.startRunning()
}
func failed() {
let ac = UIAlertController(title: "Scanning not supported", message: "Your device does not support scanning a code from an item. Please use a device with a camera.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
captureSession = nil
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if (captureSession?.isRunning == false) {
captureSession.startRunning()
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if (captureSession?.isRunning == true) {
captureSession.stopRunning()
}
}
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
captureSession.stopRunning()
if let metadataObject = metadataObjects.first {
guard let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject else { return }
guard let stringValue = readableObject.stringValue else { return }
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
found(code: stringValue)
}
dismiss(animated: true)
}
func found(code: String) {
print(code)
}
override var prefersStatusBarHidden: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
}
这是我的(非常简单的)尝试在按下按钮时打开它:
struct ScanView: View{
var body: some View{
VStack {
Button(action: {
ScannerViewController()
}) {
Text("Scan QR Code").foregroundColor(Color.white).padding()
}.frame(width: 150)
.background(Color.blue)
.cornerRadius(25)
}
}
}
我已经尝试查看有关这些类型问题的其他一些 StackOverflow 帖子,但有些帖子要么使用不推荐使用的扫描二维码的方式,要么与我面临的问题无关。
我确信这是相当简单的事情,但我的 Swift/Xcode 专业知识主要涉及设计和样式以及 API 调用的基本知识,但我不一定了解不同的视图层次结构和调用方法是如何工作的。
当然,我想解决这个问题,但我也想知道问题是什么,以便下次知道。
解决方案
我们不能直接调用UIViewController
。SwiftUI
需要UIViewControllerRepresentable
提出一个UIViewController
.
你可以在这里读到它:
- https://developer.apple.com/documentation/swiftui/uiviewcontrollerrepresentable
- https://developer.apple.com/tutorials/swiftui/interfacing-with-uikit
试试这个,它正在工作,我可以通过相机看到内容:
import SwiftUI
import UIKit
import AVFoundation
struct ScannerView: UIViewControllerRepresentable {
typealias UIViewControllerType = ScannerViewController
func updateUIViewController(_ uiViewController: ScannerViewController, context: Context) {
print("update")
}
func makeUIViewController(context: Context) -> ScannerViewController {
return ScannerViewController()
}
}
在你的struct
ScanView 中:
struct ContentView: View {
@State private var showingScanner = false
var body: some View {
VStack {
Button(action: {
self.showingScanner = true
}) {
Text("Scan QR Code").foregroundColor(Color.white).padding()
}.frame(width: 150)
.background(Color.blue)
.cornerRadius(25)
}.sheet(isPresented: $showingScanner) {
ScannerView()
}
}
}
摄像头视图,我已经将摄像头视图拖到了下面,这样您就可以在后台看到按钮屏幕:
PS不要忘记Privacy - Camera Usage Description
添加info.plist
推荐阅读
- java - 有没有办法使用 Android 的语音识别 API 来输出真/假,即使手机处于关机状态?
- python - 在 python 中用总和绘制复杂函数的 3D 绘图
- php - IF 条件,来自 cookie 的数据未验证
- vb.net - 尝试使用 ActiveX 组件在 VB 中重新创建 Pearl LWP 代码
- node.js - 带有 createSessionCookie 的 Google 登录 idToken 导致错误 - 没有与提供的标识符对应的用户记录
- python-3.x - 检查列表是否已排序 Python
- sql - 在 SQL 中不使用子查询过滤客户
- kubernetes - hpa 不与副本共享 cpu 流量
- .net - VSTO:如何写入 MS-Office 的“最近的文档”
- c# - ASP.Net Core MVC - SelectListItem 自定义属性的客户端验证