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:
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:
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:
Hope it will save you.