【问题标题】:Use an existing view as UIImagePickerController's cameraOverlayView使用现有视图作为 UIImagePickerController 的 cameraOverlayView
【发布时间】:2015-07-07 19:44:50
【问题描述】:
我有一个滚动视图,内容顶部有一个透明开口。开幕式在屏幕外开始。 (黑色矩形代表设备窗口):
当滚动视图开始向下滚动时,我想启动设备的摄像头,图像选择器视图在滚动视图后面:
滚动视图将像这样锁定到位:
透明打开和滚动视图行为没有问题。我还成功地展示了一个 UIImagePickerController 和一个自定义覆盖层,不是一个屏幕滚动视图。
我似乎无法弄清楚如何在上面模拟的现有内容背后呈现图像选择器的视图。
【问题讨论】:
标签:
objective-c
iphone
swift
uiscrollview
uiimagepickercontroller
【解决方案1】:
经过数小时的额外研究,我得出的结论是,使用 UIImagePickerController 无法做到我想要的。然而,深入研究框架堆栈,我发现了更强大(如果更复杂)的 AVCaptureSession。
解决方案概要
根据标题为“在 iOS 5 上使用 AV Foundation 从摄像头捕获”的 WWDC 视频,我制作了一个名为 VideoCaptureView 的类,它封装了输入和摄像头预览方面的等式。然后我在“舷窗”视图后面拍了一个空白的 UIView,它提供了圆形矩形遮罩,并使 UIView 成为 VideoCaptureView 的子类。使用视图控制器中的插座,当滚动视图将舷窗移动到位时,我调用 captureView.beginCapture() 。 (还没有处理停止视频捕获的问题……这是读者的练习。)
代码
对于其他感兴趣的人,这是我当前的 VideoCaptureView 实现......也在 GitHub 上作为 gist。
import UIKit
import AVFoundation
typealias VideoCaptureFailure = String
class VideoCaptureView: UIView {
var videoDataCaptureDelegate: AVCaptureVideoDataOutputSampleBufferDelegate?
private var previewLayer: AVCaptureVideoPreviewLayer?
private lazy var captureSession:AVCaptureSession = {
let session = AVCaptureSession()
print("created capture session: \(session)".emphasizeForLogging())
session.sessionPreset = AVCaptureSessionPresetPhoto
return session
}()
func beginCapture() -> VideoCaptureFailure? {
print("Stopping session: \(captureSession)".emphasizeForLogging())
captureSession.stopRunning()
if let device = captureDevice() {
var err : NSError? = nil
if captureSession.inputs.isEmpty {
captureSession.addInput(AVCaptureDeviceInput(device: device, error: &err))
}
if captureSession.outputs.isEmpty {
assert(videoDataCaptureDelegate != nil, "Hey, you forgot to hook up the damn delegate!")
let output = AVCaptureVideoDataOutput()
captureSession.addOutput(output)
let serial_queue = dispatch_queue_create("smilesVideoOutputQueue", nil)
output.setSampleBufferDelegate(videoDataCaptureDelegate, queue: serial_queue)
}
if err != nil {
println("error: \(err?.localizedDescription)".emphasizeForLogging())
}
if previewLayer == nil {
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
self.layer.addSublayer(previewLayer)
previewLayer?.frame = self.layer.frame
}
captureSession.startRunning()
return nil // Success.
} else { return "No capture device available" }
}
private func captureDevice() -> AVCaptureDevice? {
// Make sure this particular device supports video
for device in AVCaptureDevice.devices() {
if device.hasMediaType(AVMediaTypeVideo) {
if device.position == .Front {
return device as? AVCaptureDevice
}
}
}
return nil
}
}