imaginary-cloud / CameraManager

Simple Swift class to provide all the configurations you need to create custom camera view in your app
MIT License
1.37k stars 320 forks source link

CameraManager with SwiftUI? #241

Closed Vweston closed 3 years ago

Vweston commented 3 years ago

General Question about using CameraManager with SwiftUI. Is there an example of how to do this. I’m trying to figure it out, but still in a very early learning curve. Any help would be appreciated.

is there also a way to manually rotate the camera image &/or flip the camera image?

mrtksn commented 3 years ago

It works fine with UIViewControllerRepresentable. Here is an example that will attach an UIImage to the binding you pass.

To use it, create a view, your SwiftUI view where you want to have the CameraView. Your view needs to have a @State that holds the output UIImage and another @State that holds an instance of the Camera Manager.

So, in your body:

VStack {
                    if let cameraManager = self.cameraManager  {
                        CameraView(image: self.$capturedImage, cameraManager: cameraManager)
                    } else {
                        EmptyView()
                    }
                }.onAppear{
                    self.cameraManager = CameraManager()
                }.onDisappear{
                    self.cameraManager?.stopCaptureSession()
                    self.cameraManager = nil
                }

Use onAppear&onDisappear to init the CameraManager and shut off the camera afterwards. That's why I keep CameraManager as a @State. If you don't do that, you will have a greed dot on the top right corner of your screen indicating camera use and your users may think that you are secretly recording them.

struct CameraView : UIViewControllerRepresentable {

    @Binding var image : UIImage?
    let cameraManager : CameraManager?

    func makeUIViewController(context: Context) -> CMViewController {
        let vc = CMViewController(camera: .front, coordinator: context.coordinator)
        return vc
    }
    func updateUIViewController(_ uiViewController: CMViewController, context: Context) {
        print("Updated")

    }
    func makeCoordinator() -> Coordinator {
        //
        let coordinator = Coordinator(cameraManager : self.cameraManager ?? CameraManager())

        return coordinator
    }

    class Coordinator : NSObject {
        init(cameraManager: CameraManager) {
            self.cameraManager = cameraManager
        }

        let cameraManager : CameraManager
    }

    class CMViewController : UIViewController {

        let coordinator : Coordinator

        init(camera :  CameraDevice, coordinator : Coordinator) {
            self.coordinator = coordinator

            super.init(nibName: nil, bundle: nil)
            self.setCamera(camera)
        }
        func setCamera(_ camera : CameraDevice ){
            self.coordinator.cameraManager.cameraDevice = camera
            self.coordinator.cameraManager.writeFilesToPhoneLibrary = false

        }

        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }

        override func viewDidLoad() {
            self.coordinator.cameraManager.addLayerPreviewToView(self.view, newCameraOutputMode: .stillImage) {
                print("CMViewController DONE")
            }
        }
    }

}
Vweston commented 3 years ago

Thank you Mertol Kasanan, that worked. It would have taken me quite awhile to figure all of that out. Saved me a lot of trial & error. Much appreciated.

Samigos commented 1 year ago

Hi @mrtksn! I followed your code example, and I noticed a capture delay issue. If I switch between cameras and then capture a photo, it has a delay of about 2-3 seconds until the capture callback returns. After that, every time I switch the camera direction it adds to the delay.

Any idea why?

Samigos commented 1 year ago

Found the reason why https://github.com/imaginary-cloud/CameraManager/issues/114#issuecomment-320117154