iPhone Xs - 使用 AVCaptureVideoPreviewLayer 时,为啥我的 UIView 的上边框和安全区域的上边框之间有巨大的填充?

Posted

技术标签:

【中文标题】iPhone Xs - 使用 AVCaptureVideoPreviewLayer 时,为啥我的 UIView 的上边框和安全区域的上边框之间有巨大的填充?【英文标题】:iPhone Xs - Why is there a huge padding between the top border of my UIView and the top border of the safe area when using AVCaptureVideoPreviewLayer?iPhone Xs - 使用 AVCaptureVideoPreviewLayer 时,为什么我的 UIView 的上边框和安全区域的上边框之间有巨大的填充? 【发布时间】:2018-11-28 17:13:10 【问题描述】:

我正在 iphone Xs Max 上开发自定义相机。我的布局如下。唯一的 UIView 的上、左、右、下边框都锚定到了安全区域。然而,我看到的是视频捕获输出的上边框和安全视图的上边框之间的巨大黑色空间。这个黑色空间是什么?如何计算它的高度?

布局:

UIView 约束:

代码:

class NewCapturViewController: UIViewController, UIImagePickerControllerDelegate,AVCaptureVideoDataOutputSampleBufferDelegate  

   var previewLayer = AVCaptureVideoPreviewLayer.init()
   var captureSession: AVCaptureSession!


   override func viewWillAppear(_ animated: Bool) 
       startAVCaptureSession()
   


func startAVCaptureSession() 
    print("START CAPTURE SESSION!!")

    // Setting Up a Capture Session
    self.captureSession = AVCaptureSession()
    captureSession.beginConfiguration()

    // Configure input
    let videoDevice = AVCaptureDevice.default(for: .video)

    guard
        let videoDeviceInput = try? AVCaptureDeviceInput.init(device: videoDevice!) as AVCaptureInput,
        self.captureSession.canAddInput(videoDeviceInput)else return

    self.captureSession.addInput(videoDeviceInput)

    // Capture video output
    let videoOutput = AVCaptureVideoDataOutput.init()
    guard self.captureSession.canAddOutput(videoOutput) else return
    videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.init(label: "videoQueue"))
    self.captureSession.addOutput(videoOutput)


    // start
    self.captureSession.commitConfiguration()
    self.captureSession.startRunning()


    // Display camera preview
    self.previewLayer = AVCaptureVideoPreviewLayer.init(session: self.captureSession)

    // Use 'insertSublayer' to enable button to be viewable
    self.camViewOutlet.layer.insertSublayer(self.previewLayer, at: 0)
    self.previewLayer.frame = self.camViewOutlet.frame
    self.previewFrame = previewLayer.frame


    print("previewLayer.frame: \(previewLayer.frame)")






【问题讨论】:

【参考方案1】:

这是因为您已将Align Top 设置为Safe Area。请记住,这款手机有一个缺口 - 所以安全区域会更低。

如果您将Storyboard 中的电话更改为iPhone Xs(如问题中所述),您会发现您有这个差距。您需要做的就是将顶部约束设置为Superview 而不是Safe Area

【讨论】:

请您详细说明“将顶部与安全区域对齐” - 这是以编程方式进行的吗?。 @dean 在其中一张图片中,您展示了您在情节提要中所做的约束。只需单击顶部约束,并将对齐方式更改为Superview 而不是Safe Area 我按照你的建议做了,但我仍然得到那个黑色填充 @dean 我认为这应该有效。既然没有,我不太确定这个问题。如果这很重要或者您需要更多帮助,您可以随时将项目上传到 GitHub 并将其链接到您的问题中。如果您上传项目,请更新我,我会尝试整理。 谢谢乔治。我很感激。【参考方案2】:

您应该在viewDidLayoutSubviews 中设置图层框架,而不是在viewDidLoad 中。请注意,视图的大小更改,但您添加的图层保持静态,因为它们不会随容器视图自动更新:

override func viewDidLayoutSubviews() 
   super.viewDidLayoutSubviews()

   self.previewLayer.frame = self.camViewOutlet.bounds
   self.previewFrame = previewLayer.frame

还要注意framebounds 之间的区别。 camViewOutlet.frame 与其父视图 (self.view) 相关,但 previewLayer 放在 camViewOutlet 中,因此您必须使用 camViewOutlet.bounds。基本上,因为camViewOutlet是在屏幕顶部(安全区域的高度)下方放置X个点,所以previewLayer也是在camViewOutlet顶部下方放置X个点。

您的代码中还有其他小问题。

注意viewWillAppear必须调用super.viewWillAppear,它可以被多次调用,因此你不应该在其中添加视图和层。

在调用viewDidAppear 之前,您可能也不应该开始捕获。

【讨论】:

请您根据我上面关于 viewDidLayoutSubviews 的内容详细说明一些代码吗?你的回答我不是很清楚。你最后两点做得很好。 @dean 更新了一个例子。 另外,注意到bounds vs frame 的另一个问题。 您知道如何访问安全的布局边距(纵向的 top 和 borrom)吗?因为虽然黑色填充已大大减少,但似乎有一个适当的边距 - 仍然更薄的黑色空间。我快到了…… @dean 我一定还有其他问题。无论如何,顶部安全区域高度应该等于UIApplication.shared.statusBarFrame.height,也可以使用UIApplication.shared.windows[0].safeAreaInsets

以上是关于iPhone Xs - 使用 AVCaptureVideoPreviewLayer 时,为啥我的 UIView 的上边框和安全区域的上边框之间有巨大的填充?的主要内容,如果未能解决你的问题,请参考以下文章

iPhone XR / XS / XS Max CSS 媒体查询

iOS App Icon启动图尺寸配置适配iPhone XS XR XS Max等

苹果 xs无法开机要怎么办?

游戏卡在安全区域 iPhone Xs

为啥 iPhone XR、XS 和 XS Max 没有将环境图像应用到 ARKit 中的场景?

物理尺寸Iphone XS Max和Iphone XR屏幕[重复]