Home > Back-end >  Connect UIViewRepresentable to SwiftUI
Connect UIViewRepresentable to SwiftUI

Time:12-17

I have a SwiftUI based app with a simple button that when pressed is supposed to open a Camera Class from AVFoundation that utilizes UIKit as well. Under the sheet I am not sure what exactly to place there. I tried CameraSession() and a few other ideas but I am sort of lost on bridging this SwiftUI button to open camera app. Thank you!

//Content View

import SwiftUI

struct ContentView: View {
    //@State private var image: Image?
    @State private var showingCameraSession = false
    //@Binding var isShown: Bool
    var body: some View {
        VStack{
            
            ControlButton(systemIconName: "slider.horizontal.3"){
            //Button("Seelect Image") {
                showingCameraSession = true
            } .sheet(isPresented: $showingCameraSession){
            //What to place here?

                
            }
           
       }
    }
}

//CameraSession

import AVFoundation
//import RealityKit
import UIKit
import SwiftUI



struct CameraSession : UIViewControllerRepresentable {
    //@Binding var isShown: Bool
    typealias UIViewControllerType = CaptureSession
    
    func makeUIViewController(context: Context) -> CaptureSession{
        return CaptureSession()
    }

    func updateUIViewController(_ uiViewController: CaptureSession, context: Context) {
           // if(self.isShown){
                //CameraSession.didTapTakePhoto()
               // shutterButton.addTarget(self, action: #selector(didTapTakePhoto), for: .touchUpInside) //tie button to actual function
            }
        }





class CaptureSession: UIViewController {
    //@Binding var isShown: Bool
    
    
     //Reference: https://www.youtube.com/watch?v=ZYPNXLABf3c
    //CaptureSession
    var session: AVCaptureSession?
    //PhotoOutput  --> to the Cloud
    let output = AVCapturePhotoOutput()
    // Video Preview
    let previewLayer = AVCaptureVideoPreviewLayer()
    
    
    //Shutter Button
    
    private let shutterButton: UIButton = {
        let button = UIButton(frame: CGRect(x:0, y:0, width: 100, height: 100))
        button.layer.cornerRadius = 50
        button.layer.borderWidth = 10
        button.layer.borderColor = UIColor.white.cgColor
        return button
        
    }()
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .black
        //previewLayer.backgroundColor = UIColor.systemRed.cgColor
        view.layer.addSublayer(previewLayer)
        view.addSubview(shutterButton)
        checkCameraPermissions()
      
       shutterButton.addTarget(self, action: #selector(didTapTakePhoto), for: .touchUpInside) //tie button to actual function
    }
    
    override func viewDidLayoutSubviews(){
        super.viewDidLayoutSubviews()
        previewLayer.frame = view.bounds
        
        shutterButton.center = CGPoint(x: view.frame.size.width/2, y: view.frame.size.height - 100)
    }
    
    private func checkCameraPermissions() {
        switch AVCaptureDevice.authorizationStatus(for: .video){
            
        case .notDetermined:
            //Request Permission
            AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in
                guard granted else {
                    return
                }
                DispatchQueue.main.async{
                    self?.setUpCamera()
                }
            }
        case .restricted:
            break
        case .denied:
            break
        case .authorized:
            setUpCamera()
        @unknown default:
            break
        }
    }
    //with Photogrammetry, you also have to create a session similar https://developer.apple.com/documentation/realitykit/creating_3d_objects_from_photographs/
    // example app: https://developer.apple.com/documentation/realitykit/taking_pictures_for_3d_object_capture
    private func setUpCamera(){
        let session = AVCaptureSession()
        if let device = AVCaptureDevice.default(for: .video){
            do{
                let input = try AVCaptureDeviceInput(device: device)
                if session.canAddInput(input){
                    session.addInput(input) //some Devices contract each other.
                }
                if session.canAddOutput(output) {
                    session.addOutput(output)
                }
                previewLayer.videoGravity = .resizeAspectFill //content does not get distored or filled
                previewLayer.session = session
                 
                
                session.startRunning()
                self.session = session
                
            }
            catch{
                print(error)
            }
        }
    }
    //originally private
    @objc private func didTapTakePhoto() {
       
         output.capturePhoto(with: AVCapturePhotoSettings(),
                            delegate: self)
       // let vc = UIHostingController(rootView: ContentView())
       // present(vc, animated: true)
        
    }
}
 //AVCaptureOutput is AVFoundations version of photo output
extension CaptureSession: AVCapturePhotoCaptureDelegate {
    func photoOutput( output: AVCaptureOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error:
                      Error?){
                      guard let data = photo.fileDataRepresentation() else { //where to store file information
                        return
                      }
                    let image = UIImage(data: data)
        
        session?.stopRunning()
        
        let imageView = UIImageView(image: image)
        imageView.contentMode = .scaleAspectFill
        imageView.frame = view.bounds
        view.addSubview(imageView)
    }
}

CodePudding user response:

So to get around this first make your app has permission to access the users camera(go to Info.plist or info tab beside the build settings at the top and add Privacy camera usage and add "We need your camera to perform this action")

After that a simple call in the sheet's modifier should do the trick

struct ContentView: View {
    //@State private var image: Image?
    @State private var showingCameraSession = false
    //@Binding var isShown: Bool
    var body: some View {
        VStack{
            
//            ControlButton(systemIconName: "slider.horizontal.3"){
            Button("Seelect Image") {
                showingCameraSession = true
            } .sheet(isPresented: $showingCameraSession){
            //What to place here?
                
                CameraSession()

                
            }
           
       }
    }
}
  • Related