developerAvatar
developerAvatar

Reputation: 43

AVSampleBufferDisplayLayer in SwiftUI in UIViewRepresentable

I want to add AVSampleBufferDisplayLayer in top if my UIImageView but I need access to that AVSampleBufferDisplayLayer as a property. The Error self is not immutable is shown.


struct CamerImageSUIView: UIViewRepresentable {
    
    internal lazy var cameraAVLayer: AVSampleBufferDisplayLayer = {
        let avLayer = AVSampleBufferDisplayLayer()
        avLayer.videoGravity = .resizeAspectFill
        return avLayer
    }()

    func makeUIView(context: Context)  -> ImageLoaderView {
        let imageView = ImageLoaderView()
        imageView.ribbonMode = false
        imageView.event = false
        imageView.tintColor = UIColor(named: "ColorC5")
        imageView.backgroundColor = UIColor(named: "ColorC3")
        imageView.contentMode = .scaleToFill

        //HERE IS THE PROBLEM BECAUSE cameraAVLayer is immutable
        imageView.layer.insertSublayer(cameraAVLayer, at: 0)
        cameraAVLayer.frame = imageView.layer.bounds

        return imageView
    }

    func updateUIView(_ uiView: ImageLoaderView, context: Context) {}
    
    
}

Upvotes: 0

Views: 1014

Answers (1)

Satoshi Nakajima
Satoshi Nakajima

Reputation: 2143

I had a similar issue with my app, and came up with the following implementation.

  1. Created a model object, which has a displayLayer property.
class CameraImageState: ObservableObject {
    let displayLayer = AVSampleBufferDisplayLayer()
}
  1. When I create a view, I give the reference to this model object (or the displayLayer property)
struct CamerImageSUIView: UIViewRepresentable {
    @ObservedObject var state: CameraImageState
    
    func makeUIView(context: Context)  -> ImageLoaderView {
        let imageView = ImageLoaderView()
        imageView.ribbonMode = false
        imageView.event = false
        imageView.tintColor = UIColor(named: "ColorC5")
        imageView.backgroundColor = UIColor(named: "ColorC3")
        imageView.contentMode = .scaleToFill

        state.displayLayer.videoGravity = .resizeAspectFill
        state.displayLayer.frame = imageView.layer.bounds
        imageView.layer.insertSublayer(state.displayLayer, at: 0)

        return imageView
    }

    func updateUIView(_ uiView: ImageLoaderView, context: Context) {}
}

By the way, (even though I haven't modified your code) it does not make sense to set the frame of displayLayer in makeUIView, because it will change later anyway. You need to do it in layoutsubviews() of ImageLoaderView.

Upvotes: 1

Related Questions