Notes on how to implement camera functionality in SwiftUI.
Implementing the basic functionality
import SwiftUI
import AVFoundation
struct CameraContentView: View {
var body: some View {
CameraView()
.edgesIgnoringSafeArea(.all)
}
}
struct CameraView: UIViewRepresentable {
func makeUIView(context: Context) -> UIView { BaseCameraView() }
func updateUIView(_ uiView: UIViewType, context: Context) {}
}
class BaseCameraView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
_ = initCaptureSession
(layer.sublayers?.first as? AVCaptureVideoPreviewLayer)?.frame = bounds
}
lazy var initCaptureSession: Void = {
guard let device = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera],
mediaType: .video,
position: .unspecified)
.devices.first(where: { $0.position == .front }),
let input = try? AVCaptureDeviceInput(device: device) else { return }
let session = AVCaptureSession()
session.addInput(input)
session.startRunning()
layer.insertSublayer(AVCaptureVideoPreviewLayer(session: session), at: 0)
}()
}
Running this code launches the front camera and displays its feed across the full screen.
Rotating the camera to match the screen orientation
As is, when you rotate the device, the preview keeps its 16:9 portrait/landscape ratio while rotating along with it, so the camera feed no longer matches the screen's orientation.
So I added the following code.
enum Orientation: Int {
case right = -1, down = 0, left = 1, up = 2
}
private func getDeviceOrientation() -> Orientation {
guard let interfaceOrientation = UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.windowScene?.interfaceOrientation else {
return .right
}
switch interfaceOrientation {
case .landscapeLeft:
return .left
case .landscapeRight:
return .right
case .portrait:
return .down
case .portraitUpsideDown:
return .up
default:
return .right
}
}
private func fixCameraOrientation() {
let rotation: CGFloat = CGFloat(getDeviceOrientation().rawValue) * 90
previewLayer?.transform = CATransform3DMakeRotation(rotation / 180 * CGFloat.pi, 0, 0, 1)
}
Adding these functions to layoutSubviews makes the camera orientation adjust correctly every time the device orientation changes.
References
This article was a huge help, thank you