Я пытаюсь добавить QR-сканер в свое приложение, в корне которого есть представление вкладок. Это работает, за исключением одного; Когда появляется диалоговое окно с запросом у пользователя разрешения на использование камеры, оно также автоматически переключает выбранную вкладку со второй вкладки на первую, которая появляется в коде. Если я поменяю местами в коде между CameraView
и AnyView
, все будет работать как положено, но я не хочу, чтобы вкладка с CameraView была первой вкладкой.
Я воспроизвел это в следующем примере:
КонтентВью:
import SwiftUI
enum Tab: Int {
case first = 1, second
}
struct ContentView: View {
@SceneStorage("selectedTab") var selectedTab: Int?
init() {
selectedTab = Tab.first.rawValue
}
var body: some View {
TabView {
TabView(selection: $selectedTab) {
AnyView()
.tabItem {
Label("Calendar", systemImage: "calendar")
}
.tag(Tab.first)
CameraView()
.tabItem {
Label("Camera", systemImage: "person.fill")
}
.tag(Tab.second)
}
.padding()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Вид камеры:
import SwiftUI
import UIKit
import AVFoundation
struct CameraView: UIViewRepresentable {
typealias UIViewType = CameraPreview
private let session = AVCaptureSession()
private let metadataOutput = AVCaptureMetadataOutput()
func setupCamera(_ uiView: CameraPreview) {
if let backCamera = AVCaptureDevice.default(for: AVMediaType.video) {
if let input = try? AVCaptureDeviceInput(device: backCamera) {
session.sessionPreset = .photo
if session.canAddInput(input) {
session.addInput(input)
}
if session.canAddOutput(metadataOutput) {
session.addOutput(metadataOutput)
}
let previewLayer = AVCaptureVideoPreviewLayer(session: session)
uiView.backgroundColor = UIColor.gray
previewLayer.videoGravity = .resizeAspectFill
uiView.layer.addSublayer(previewLayer)
uiView.previewLayer = previewLayer
session.startRunning()
}
}
}
func makeUIView(context: UIViewRepresentableContext<CameraView>) -> CameraView.UIViewType {
let cameraView = CameraPreview(session: session)
checkCameraAuthorizationStatus(cameraView)
return cameraView
}
static func dismantleUIView(_ uiView: CameraPreview, coordinator: ()) {
uiView.session.stopRunning()
}
private func checkCameraAuthorizationStatus(_ uiView: CameraPreview) {
let cameraAuthorizationStatus = AVCaptureDevice.authorizationStatus(for: .video)
if cameraAuthorizationStatus == .authorized {
setupCamera(uiView)
} else {
AVCaptureDevice.requestAccess(for: .video) { granted in
DispatchQueue.main.sync {
if granted {
self.setupCamera(uiView)
}
}
}
}
}
func updateUIView(_ uiView: CameraPreview, context: UIViewRepresentableContext<CameraView>) {
uiView.setContentHuggingPriority(.defaultHigh, for: .vertical)
uiView.setContentHuggingPriority(.defaultLow, for: .horizontal)
}
}
Предварительный просмотр камеры:
import UIKit
import AVFoundation
class CameraPreview: UIView {
private var label:UILabel?
var previewLayer: AVCaptureVideoPreviewLayer?
var session = AVCaptureSession()
init(session: AVCaptureSession) {
super.init(frame: .zero)
self.session = session
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
previewLayer?.frame = self.bounds
}
}
Любые идеи о том, почему это может происходить или как я могу это исправить или обойти это?
Прочитав немного о SceneStorage, я начал задаваться вопросом, не это ли создавало проблему. Я переключил @SceneStorage("selectedTab") var selectedTab: Int?
на @State var selectedTab: Int?
, но это не сработало.
Посмотрев на собственный пример Apple того, как создать представление вкладок, я понял, что, возможно, синтаксис был немного изменен.
После перехода на:
enum Tab {
case first <-- this is different
case second
}
struct ContentView: View {
@State var selectedTab: Tab = .first <-- this is different
var body: some View {
TabView {
TabView(selection: $selectedTab) {
AnyView()
.tabItem {
Label("Calendar", systemImage: "calendar")
}
.tag(Tab.first)
AddFriend()
.tabItem {
Label("Camera", systemImage: "person.fill")
}
.tag(Tab.second)
}
.padding()
}
}
}
проблема больше не сохранялась. Я предполагаю, что то, как я инициализировал вкладку по умолчанию, заставило ее вести себя неожиданным образом.