我的应用程序出现问题。我正在尝试在视图内构建条形码读取器。当我第一次启动视图时,阅读器工作正常,但如果我切换到另一个视图,然后返回到上一个视图(条形码所在的位置),我的相机就会停止工作。我想让它在每次切换回条形码所在的视图时都能正常工作。
这是我的代码:
import AVKit
import Foundation
import SwiftUI
import VisionKit
enum ScanType: String {
case barcode, text
}
enum DataScannerAccessStatusType {
case notDetermined
case cameraAccessNotGranted
case cameraNotAvailable
case scannerAvailable
case scannerNotAvailable
}
@MainActor
final class ScannerDataViewModel: ObservableObject {
@State private var session: AVCaptureSession = .init()
@Published var dataScannerAccessStatus: DataScannerAccessStatusType = .notDetermined
@Published var recognizedItems: [RecognizedItem] = []
@Published var scanType: ScanType = .barcode
@Published var textContentType: DataScannerViewController.TextContentType?
@Published var recognizesMultipleItems = true
var recognizedDataType: DataScannerViewController.RecognizedDataType {
scanType == .barcode ? .barcode() : .text(textContentType: textContentType)
}
var headerText: String {
if recognizedItems.isEmpty {
return "Scansione \(scanType.rawValue)"
} else {
return "Riconosciuti \(recognizedItems.count) oggetti"
}
}
var dataScannerViewId: Int {
var hasher = Hasher()
hasher.combine(scanType)
hasher.combine(recognizesMultipleItems)
if let textContentType {
hasher.combine(textContentType)
}
return hasher.finalize()
}
private var isScannerAvailable: Bool {
DataScannerViewController.isAvailable && DataScannerViewController.isSupported
}
func requestDataScannerAccessStatus() async {
guard UIImagePickerController.isSourceTypeAvailable(.camera) else {
dataScannerAccessStatus = .cameraNotAvailable
return
}
switch AVCaptureDevice.authorizationStatus(for: .video) {
case .authorized:
dataScannerAccessStatus = isScannerAvailable ? .scannerAvailable : .scannerNotAvailable
case .restricted, .denied:
dataScannerAccessStatus = .cameraAccessNotGranted
case .notDetermined:
let granted = await AVCaptureDevice.requestAccess(for: .video)
if granted {
dataScannerAccessStatus = isScannerAvailable ? .scannerAvailable : .scannerNotAvailable
} else {
dataScannerAccessStatus = .cameraAccessNotGranted
}
default: break
}
}
}
这是 DataScannerView:
import Foundation
import SwiftUI
import VisionKit
struct DataScannerView: UIViewControllerRepresentable {
@Binding var recognizedItems: [RecognizedItem]
let recognizedDataType: DataScannerViewController.RecognizedDataType
let recognizesMultipleItems: Bool
func makeUIViewController(context: Context) -> DataScannerViewController {
let vc = DataScannerViewController(
recognizedDataTypes: [recognizedDataType],
qualityLevel: .balanced,
recognizesMultipleItems: recognizesMultipleItems,
isGuidanceEnabled: true,
isHighlightingEnabled: true
)
return vc
}
func updateUIViewController(_ uiViewController: DataScannerViewController, context: Context) {
uiViewController.delegate = context.coordinator
try? uiViewController.startScanning()
}
func makeCoordinator() -> Coordinator {
Coordinator(recognizedItems: $recognizedItems)
}
static func dismantleUIViewController(_ uiViewController: DataScannerViewController, coordinator: Coordinator) {
uiViewController.stopScanning()
}
class Coordinator: NSObject, DataScannerViewControllerDelegate {
@Binding var recognizedItems: [RecognizedItem]
init(recognizedItems: Binding<[RecognizedItem]>) {
self._recognizedItems = recognizedItems
}
func dataScanner(_ dataScanner: DataScannerViewController, didTapOn item: RecognizedItem) {
print("didTapOn \(item)")
}
func dataScanner(_ dataScanner: DataScannerViewController, didAdd addedItems: [RecognizedItem], allItems: [RecognizedItem]) {
UINotificationFeedbackGenerator().notificationOccurred(.success)
recognizedItems.append(contentsOf: addedItems)
print("didAddItems \(addedItems)")
}
func dataScanner(_ dataScanner: DataScannerViewController, didRemove removedItems: [RecognizedItem], allItems: [RecognizedItem]) {
self.recognizedItems = recognizedItems.filter { item in
!removedItems.contains(where: {$0.id == item.id })
}
print("didRemovedItems \(removedItems)")
}
func dataScanner(_ dataScanner: DataScannerViewController, becameUnavailableWithError error: DataScannerViewController.ScanningUnavailable) {
print("became unavailable with error \(error.localizedDescription)")
}
}
}
最后,这是我想展示我的条形码阅读器的视图:
import SwiftUI
struct ScanView: View {
@Environment(\.presentationMode) var presentationMode
@StateObject private var vm: ScannerDataViewModel = ScannerDataViewModel()
private let viewInsideScan = ViewInsideScanView()
var body: some View {
NavigationView {
ZStack {
Color("whiteBackground").ignoresSafeArea()
VStack(spacing: 8) {
Text("Posiziona il codice a barre al centro")
.font(.title3)
.foregroundColor(Color.primary)
.padding(.top, 20)
Text("La scansione inizierà automaticamente")
.font(.callout)
.foregroundColor(Color.primary)
Spacer()
CenteredSquareView(content: viewInsideScan)
.frame(width: 350, height: 350, alignment: .center)
Spacer()
Image(systemName: "qrcode.viewfinder")
.font(.largeTitle)
.foregroundColor(.gray)
Text("Tocca l'icona per eseguire una nuova scansione")
.font(.callout)
.foregroundColor(Color.primary)
Spacer(minLength: 45)
}
}
.environmentObject(vm)
.onAppear {
Task {
await vm.requestDataScannerAccessStatus()
}
}
}
}
}
struct CenteredSquareView<Content: View>: View {
var content: Content
var body: some View {
GeometryReader { geometry in
ZStack {
content
.frame(width: geometry.size.width * 1, height: geometry.size.width * 1)
.cornerRadius(20)
.position(x: geometry.size.width / 2, y: geometry.size.height / 2) // Posiziona al centro
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
#Preview {
ScanView()
}
我知道,这太令人困惑了。我是一名初级开发人员,我正在努力变得更好。我注意到,每次我切换到阅读器所在的视图时,我的相机都会工作几秒钟,然后停止。 谢谢大家的帮助!
看来该问题可能与 ScanView 中使用 DataScannerView 的方式有关。具体来说,当您切换到另一个视图然后返回时,将重新创建 DataScannerView,并且它可能无法正确处理返回到视图的转换。
尝试修改 DataScannerView 以更明确地处理扫描会话的启动和停止。您可以通过使用 onAppear 和 onDisappear 修饰符在视图出现和消失时启动和停止扫描会话来完成此操作。
在 GitHub 中分享您的项目以进行检查。