预览层不受 UIView 的限制

Preview layer not being constrained to UIView

我下面的 Swift 代码试图将 previewLayer 限制在名为相机视图的 UIView 的边界。然而,这并没有发生。 previewLayer 比约束 cameraView UIView 大很多。 cameraView 受到故事板约束的约束。我只希望 2 个对象的位置和大小相同。

           import AVFoundation;import UIKit
    class ViewController: UIViewController, AVCaptureFileOutputRecordingDelegate {
    func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {

    }


    var captureSession = AVCaptureSession()
    var sessionOutput = AVCaptureStillImageOutput()
    var movieOutput = AVCaptureMovieFileOutput()
    var previewLayer = AVCaptureVideoPreviewLayer()

    @IBOutlet var cameraView: UIView!



    override func viewWillAppear(_ animated: Bool) {


        let devices = AVCaptureDevice.devices(for: AVMediaType.video)
        for device in devices {
            if device.position == AVCaptureDevice.Position.front{


                do{

                    let input = try AVCaptureDeviceInput(device: device )

                    if captureSession.canAddInput(input){

                        captureSession.addInput(input)
                        sessionOutput.outputSettings = [AVVideoCodecKey : AVVideoCodecType.jpeg]

                        if captureSession.canAddOutput(sessionOutput){

                            captureSession.addOutput(sessionOutput)




                        }

                        captureSession.addOutput(movieOutput)

                        captureSession.startRunning()

                        _ = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
                        let documentURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
                        let fileURL = documentURL.appendingPathComponent("tempImage.jpg")
                        try? FileManager.default.removeItem(at: fileURL)
                        movieOutput.startRecording(to: fileURL, recordingDelegate: self)


                        let deadlineTime = DispatchTime.now() + .seconds(1)
                        DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
                            print("test")
                            self.movieOutput.stopRecording()
                        }



                    }

                }
                catch{

                    print("Error")
                }

            }
            viewDidAppear(animated )
        }

        func viewdidappeare(_ animated: Bool) {
            previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
            self.previewLayer.frame = self.cameraView.bounds
            previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
            previewLayer.connection!.videoOrientation = AVCaptureVideoOrientation.portrait
            self.cameraView.layer.insertSublayer(self.previewLayer, at: 0)





        }






    func captureOutput(captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAtURL outputFileURL: NSURL!, fromConnections connections: [AnyObject]!, error: NSError!) {
        print("FINISHED \(error)")
        // save video to camera roll
        if error == nil {
            UISaveVideoAtPathToSavedPhotosAlbum(outputFileURL.path!, nil, nil, nil)
        }
    }

    }
    }

您可以按以下方式尝试:

override func viewDidAppear(_ animated: Bool) { 
       super.viewDidAppear(animated)
       self.previewLayer.frame = self.cameraView.bounds
 }

previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
previewLayer.connection!.videoOrientation = AVCaptureVideoOrientation.portrait
self.cameraView.layer.insertSublayer(self.previewLayer, at: 0)

所以您的完整更新代码:

import AVFoundation
import UIKit

class ViewController: UIViewController, AVCaptureFileOutputRecordingDelegate {

    func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {

    }


    var captureSession = AVCaptureSession()
    var sessionOutput = AVCaptureStillImageOutput()
    var movieOutput = AVCaptureMovieFileOutput()
    var previewLayer = AVCaptureVideoPreviewLayer()

    @IBOutlet var cameraView: UIView!


    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.previewLayer.frame = self.cameraView.bounds

    }

    override func viewWillAppear(_ animated: Bool) {


        let devices = AVCaptureDevice.devices(for: AVMediaType.video)
        for device in devices {
            if device.position == AVCaptureDevice.Position.front{


                do{

                    let input = try AVCaptureDeviceInput(device: device )

                    if captureSession.canAddInput(input){

                        captureSession.addInput(input)
                        sessionOutput.outputSettings = [AVVideoCodecKey : AVVideoCodecType.jpeg]

                        if captureSession.canAddOutput(sessionOutput){

                            captureSession.addOutput(sessionOutput)

                            previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)

                            previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
                            previewLayer.connection!.videoOrientation = AVCaptureVideoOrientation.portrait
                            self.cameraView.layer.insertSublayer(self.previewLayer, at: 0)


                        }

                        captureSession.addOutput(movieOutput)

                        captureSession.startRunning()

                        _ = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
                        let documentURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
                        let fileURL = documentURL.appendingPathComponent("tempImage.jpg")
                        try? FileManager.default.removeItem(at: fileURL)
                        movieOutput.startRecording(to: fileURL, recordingDelegate: self)


                        let deadlineTime = DispatchTime.now() + .seconds(1)
                        DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
                            print("test")
                            self.movieOutput.stopRecording()
                        }



                    }

                }
                catch{

                    print("Error")
                }

            }
        }
    }

    func captureOutput(captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAtURL outputFileURL: NSURL!, fromConnections connections: [AnyObject]!, error: NSError!) {
        print("FINISHED \(error)")
        // save video to camera roll
        if error == nil {
            UISaveVideoAtPathToSavedPhotosAlbum(outputFileURL.path!, nil, nil, nil)
        }
    }
}

问题是子层在其父层改变其大小时不会自动调整大小。您需要手动执行此操作,例如在 layoutSublayers:

override func layoutSublayers(of layer: CALayer) {
    previewLayer.bounds = cameraView.frame
}