Home > Software design >  Camera view hides TabView
Camera view hides TabView

Time:03-31

I've implemented a simple camera view:

import SwiftUI
import AVFoundation

struct CameraView: View {
    @StateObject var model = CameraModel()
    var body: some View {
        CameraPreview(camera: model).ignoresSafeArea().onAppear() {
            model.check()
        }
    }
}

struct CameraPreview: UIViewRepresentable {
    @ObservedObject var camera: CameraModel
    
    func makeUIView(context: Context) -> some UIView {
        let view = UIView(frame: UIScreen.main.bounds)
        camera.preview = AVCaptureVideoPreviewLayer(session: camera.session)
        camera.preview.frame = view.frame
        camera.preview.videoGravity = AVLayerVideoGravity.resizeAspectFill
        view.layer.addSublayer(camera.preview)
        camera.session.startRunning()
        return view
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
    }
}

struct CameraView_Previews: PreviewProvider {
    static var previews: some View {
        CameraView()
    }
}

class CameraModel: ObservableObject {
    @Published var session = AVCaptureSession()
    @Published var alert = false
    @Published var preview: AVCaptureVideoPreviewLayer!
    
    func check() {
        switch AVCaptureDevice.authorizationStatus(for: .video) {
        case .authorized:
            setUp()
            break
        case .notDetermined:
            AVCaptureDevice.requestAccess(for: .video) { (status) in
                if status {
                    self.setUp()
                }
            }
            break
        case .denied:
            self.alert.toggle()
            break
        default:
            break
        }
    }
    
    func setUp() {
        do {
            self.session.beginConfiguration()
            let device = AVCaptureDevice.default(.builtInDualCamera, for: .video, position: .back)
            let input = try AVCaptureDeviceInput(device: device!)
            
            if self.session.canAddInput(input) {
                self.session.addInput(input)
            }
            
            self.session.commitConfiguration()
        }
        catch {
            print(error.localizedDescription)
        }
    }
}

And show it as a tab in TabView (root layer):

import SwiftUI

struct ContentView: View {
    var body: some View {
        TabView {
            HomeView()
                 .tabItem {
                     Image("HomeIcon").renderingMode(.template)
                    Text("Home")
                 }
            CameraView()
                 .tabItem {
                    Image("MapMarkerRadiusIcon").renderingMode(.template)
                    Text("Camera")
                  }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Unfortunately, CameraView() overlays the bottom tab bar:

Screenshot

Looks okay? Unfortunately, no... It shows unselected icons when I am making a screenshot or going to hide app. When app is just launched and Camera tab is opened, it looks as below:

Screenshot 2

How to fix this bug? I need to the tab bar was on the top always (like on the first screenshot)

CodePudding user response:

If you want to see all tabs over camera view, there is only one workaround but it doesn't match what you showed in your first screenshot excatly.

To see all tabs, just add safeAreaInset(edge:alignment:spacing:_:) modifier right below CameraPreview(camera: model) and set ignoresSafeArea to .top.

Here is the complete sample code:

CameraPreview(camera: model)
    .safeAreaInset(edge: .bottom, alignment: .center, spacing: 0) {
        Color.clear
            .frame(height: 0)
            .background(Material.bar)
    }
    .ignoresSafeArea(.all, edges: .top)

The result:

Camera View with all Tabs

Hope it will save you.

  • Related