As an initial test for something more complex, I want to make a simple app that takes a picture when pressing a button and displays it directly within the app, without opening the camera view, and without the camera sound. The best I could come up with is the following code, but still the camera view pops up for a fraction of second before disappearing.
I found a few threads on this but those are about 10 years old and I’m not able to apply the solutions given there.
import SwiftUI
import AVFoundation
struct ContentView: View {
@State private var image: UIImage?
@State private var showCamera = false
var body: some View {
VStack {
if let image = image {
Image(uiImage: image)
.resizable()
.scaledToFit()
.frame(width: 300, height: 300)
} else {
Image(systemName: "photo")
.resizable()
.scaledToFit()
.frame(width: 300, height: 300)
.foregroundColor(.gray)
}
Button(action: {
showCamera = true
}) {
Text("Take Photo")
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
.sheet(isPresented: $showCamera) {
CameraView(image: $image, isShown: $showCamera)
}
}
.padding()
}
}
struct CameraView: UIViewControllerRepresentable {
@Binding var image: UIImage?
@Binding var isShown: Bool
class Coordinator: NSObject, AVCapturePhotoCaptureDelegate {
var parent: CameraView
init(parent: CameraView) {
self.parent = parent
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if let error = error {
print("Error capturing photo: (error.localizedDescription)")
return
}
guard let imageData = photo.fileDataRepresentation() else { return }
parent.image = UIImage(data: imageData)
parent.isShown = false
}
}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
func makeUIViewController(context: Context) -> UIViewController {
let viewController = UIViewController()
let captureSession = AVCaptureSession()
captureSession.sessionPreset = .photo
guard let videoCaptureDevice = AVCaptureDevice.default(for: .video) else { return viewController }
let videoInput: AVCaptureDeviceInput
do {
videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
} catch {
return viewController
}
if captureSession.canAddInput(videoInput) {
captureSession.addInput(videoInput)
} else {
return viewController
}
let photoOutput = AVCapturePhotoOutput()
if captureSession.canAddOutput(photoOutput) {
captureSession.addOutput(photoOutput)
} else {
return viewController
}
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.frame = viewController.view.bounds
previewLayer.videoGravity = .resizeAspectFill
viewController.view.layer.addSublayer(previewLayer)
captureSession.startRunning()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
let settings = AVCapturePhotoSettings()
settings.flashMode = .off // Make sure flash is off
photoOutput.capturePhoto(with: settings, delegate: context.coordinator)
}
return viewController
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}
user655870 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.