Ios 如何将实时摄影机预览添加到UIView
我遇到了一个问题,我正试图在UIView边界内解决,有没有办法将相机预览添加到UIView?并在UIView顶部添加其他内容(按钮、标签等)Ios 如何将实时摄影机预览添加到UIView,ios,iphone,swift,avfoundation,Ios,Iphone,Swift,Avfoundation,我遇到了一个问题,我正试图在UIView边界内解决,有没有办法将相机预览添加到UIView?并在UIView顶部添加其他内容(按钮、标签等) 我尝试使用AVFoundation框架,但没有足够的文档用于Swift。更新为Swift 5 您可以尝试以下方法: import UIKit import AVFoundation class ViewController: UIViewController{ var previewView : UIView! var boxView:U
我尝试使用AVFoundation框架,但没有足够的文档用于Swift。更新为Swift 5 您可以尝试以下方法:
import UIKit
import AVFoundation
class ViewController: UIViewController{
var previewView : UIView!
var boxView:UIView!
let myButton: UIButton = UIButton()
//Camera Capture requiered properties
var videoDataOutput: AVCaptureVideoDataOutput!
var videoDataOutputQueue: DispatchQueue!
var previewLayer:AVCaptureVideoPreviewLayer!
var captureDevice : AVCaptureDevice!
let session = AVCaptureSession()
override func viewDidLoad() {
super.viewDidLoad()
previewView = UIView(frame: CGRect(x: 0,
y: 0,
width: UIScreen.main.bounds.size.width,
height: UIScreen.main.bounds.size.height))
previewView.contentMode = UIView.ContentMode.scaleAspectFit
view.addSubview(previewView)
//Add a view on top of the cameras' view
boxView = UIView(frame: self.view.frame)
myButton.frame = CGRect(x: 0, y: 0, width: 200, height: 40)
myButton.backgroundColor = UIColor.red
myButton.layer.masksToBounds = true
myButton.setTitle("press me", for: .normal)
myButton.setTitleColor(UIColor.white, for: .normal)
myButton.layer.cornerRadius = 20.0
myButton.layer.position = CGPoint(x: self.view.frame.width/2, y:200)
myButton.addTarget(self, action: #selector(self.onClickMyButton(sender:)), for: .touchUpInside)
view.addSubview(boxView)
view.addSubview(myButton)
self.setupAVCapture()
}
override var shouldAutorotate: Bool {
if (UIDevice.current.orientation == UIDeviceOrientation.landscapeLeft ||
UIDevice.current.orientation == UIDeviceOrientation.landscapeRight ||
UIDevice.current.orientation == UIDeviceOrientation.unknown) {
return false
}
else {
return true
}
}
@objc func onClickMyButton(sender: UIButton){
print("button pressed")
}
}
// AVCaptureVideoDataOutputSampleBufferDelegate protocol and related methods
extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate{
func setupAVCapture(){
session.sessionPreset = AVCaptureSession.Preset.vga640x480
guard let device = AVCaptureDevice
.default(AVCaptureDevice.DeviceType.builtInWideAngleCamera,
for: .video,
position: AVCaptureDevice.Position.back) else {
return
}
captureDevice = device
beginSession()
}
func beginSession(){
var deviceInput: AVCaptureDeviceInput!
do {
deviceInput = try AVCaptureDeviceInput(device: captureDevice)
guard deviceInput != nil else {
print("error: cant get deviceInput")
return
}
if self.session.canAddInput(deviceInput){
self.session.addInput(deviceInput)
}
videoDataOutput = AVCaptureVideoDataOutput()
videoDataOutput.alwaysDiscardsLateVideoFrames=true
videoDataOutputQueue = DispatchQueue(label: "VideoDataOutputQueue")
videoDataOutput.setSampleBufferDelegate(self, queue:self.videoDataOutputQueue)
if session.canAddOutput(self.videoDataOutput){
session.addOutput(self.videoDataOutput)
}
videoDataOutput.connection(with: .video)?.isEnabled = true
previewLayer = AVCaptureVideoPreviewLayer(session: self.session)
previewLayer.videoGravity = AVLayerVideoGravity.resizeAspect
let rootLayer :CALayer = self.previewView.layer
rootLayer.masksToBounds=true
previewLayer.frame = rootLayer.bounds
rootLayer.addSublayer(self.previewLayer)
session.startRunning()
} catch let error as NSError {
deviceInput = nil
print("error: \(error.localizedDescription)")
}
}
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
// do stuff here
}
// clean up AVCapture
func stopCamera(){
session.stopRunning()
}
}
在这里,我使用名为previewView的UIView
启动相机,然后在previewView上方添加名为boxView的新UIView
。我向boxView添加了一个ui按钮
重要
请记住,在iOS 10及更高版本中,您需要首先向用户请求权限,才能访问摄像头。您可以通过添加用法来实现这一点
在应用程序的Info.plist
中键入和目的字符串
因为如果你没有声明使用情况,你的应用程序在使用时会崩溃
首先是进入
这里有一个屏幕截图显示摄像头访问请求
Swift 3:
@IBOutlet weak var cameraContainerView:UIView!
var imagePickers:UIImagePickerController?
在ViewDidLoad上:
override func viewDidLoad() {
super.viewDidLoad()
addImagePickerToContainerView()
}
func addImagePickerToContainerView(){
imagePickers = UIImagePickerController()
if UIImagePickerController.isCameraDeviceAvailable( UIImagePickerControllerCameraDevice.front) {
imagePickers?.delegate = self
imagePickers?.sourceType = UIImagePickerControllerSourceType.camera
//add as a childviewcontroller
addChildViewController(imagePickers!)
// Add the child's View as a subview
self.cameraContainerView.addSubview((imagePickers?.view)!)
imagePickers?.view.frame = cameraContainerView.bounds
imagePickers?.allowsEditing = false
imagePickers?.showsCameraControls = false
imagePickers?.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
}
@IBAction func cameraButtonPressed(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.camera){
imagePickers?.takePicture()
} else{
//Camera not available.
}
}
将相机预览添加到容器视图:
override func viewDidLoad() {
super.viewDidLoad()
addImagePickerToContainerView()
}
func addImagePickerToContainerView(){
imagePickers = UIImagePickerController()
if UIImagePickerController.isCameraDeviceAvailable( UIImagePickerControllerCameraDevice.front) {
imagePickers?.delegate = self
imagePickers?.sourceType = UIImagePickerControllerSourceType.camera
//add as a childviewcontroller
addChildViewController(imagePickers!)
// Add the child's View as a subview
self.cameraContainerView.addSubview((imagePickers?.view)!)
imagePickers?.view.frame = cameraContainerView.bounds
imagePickers?.allowsEditing = false
imagePickers?.showsCameraControls = false
imagePickers?.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
}
@IBAction func cameraButtonPressed(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.camera){
imagePickers?.takePicture()
} else{
//Camera not available.
}
}
自定义按钮操作:
override func viewDidLoad() {
super.viewDidLoad()
addImagePickerToContainerView()
}
func addImagePickerToContainerView(){
imagePickers = UIImagePickerController()
if UIImagePickerController.isCameraDeviceAvailable( UIImagePickerControllerCameraDevice.front) {
imagePickers?.delegate = self
imagePickers?.sourceType = UIImagePickerControllerSourceType.camera
//add as a childviewcontroller
addChildViewController(imagePickers!)
// Add the child's View as a subview
self.cameraContainerView.addSubview((imagePickers?.view)!)
imagePickers?.view.frame = cameraContainerView.bounds
imagePickers?.allowsEditing = false
imagePickers?.showsCameraControls = false
imagePickers?.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}
}
@IBAction func cameraButtonPressed(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(.camera){
imagePickers?.takePicture()
} else{
//Camera not available.
}
}
Swift 4 mauricioconde溶液的浓缩版本 您可以将其用作插入式组件:
//
// CameraView.swift
import Foundation
import AVFoundation
import UIKit
final class CameraView: UIView {
private lazy var videoDataOutput: AVCaptureVideoDataOutput = {
let v = AVCaptureVideoDataOutput()
v.alwaysDiscardsLateVideoFrames = true
v.setSampleBufferDelegate(self, queue: videoDataOutputQueue)
v.connection(with: .video)?.isEnabled = true
return v
}()
private let videoDataOutputQueue: DispatchQueue = DispatchQueue(label: "JKVideoDataOutputQueue")
private lazy var previewLayer: AVCaptureVideoPreviewLayer = {
let l = AVCaptureVideoPreviewLayer(session: session)
l.videoGravity = .resizeAspect
return l
}()
private let captureDevice: AVCaptureDevice? = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)
private lazy var session: AVCaptureSession = {
let s = AVCaptureSession()
s.sessionPreset = .vga640x480
return s
}()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
contentMode = .scaleAspectFit
beginSession()
}
private func beginSession() {
do {
guard let captureDevice = captureDevice else {
fatalError("Camera doesn't work on the simulator! You have to test this on an actual device!")
}
let deviceInput = try AVCaptureDeviceInput(device: captureDevice)
if session.canAddInput(deviceInput) {
session.addInput(deviceInput)
}
if session.canAddOutput(videoDataOutput) {
session.addOutput(videoDataOutput)
}
layer.masksToBounds = true
layer.addSublayer(previewLayer)
previewLayer.frame = bounds
session.startRunning()
} catch let error {
debugPrint("\(self.self): \(#function) line: \(#line). \(error.localizedDescription)")
}
}
override func layoutSubviews() {
super.layoutSubviews()
previewLayer.frame = bounds
}
}
extension CameraView: AVCaptureVideoDataOutputSampleBufferDelegate {}
斯威夫特5
捷径
iOS 13/14和Swift 5.3:
private var imageVC: UIImagePickerController?
然后在要显示相机视图时调用showCameraVC()
func showCameraVC() {
self.imageVC = UIImagePickerController()
if UIImagePickerController.isCameraDeviceAvailable(.front) {
self.imageVC?.sourceType = .camera
self.imageVC?.cameraDevice = .front
self.imageVC?.showsCameraControls = false
let screenSize = UIScreen.main.bounds.size
let cameraAspectRatio = CGFloat(4.0 / 3.0)
let cameraImageHeight = screenSize.width * cameraAspectRatio
let scale = screenSize.height / cameraImageHeight
self.imageVC?.cameraViewTransform = CGAffineTransform(translationX: 0, y: (screenSize.height - cameraImageHeight)/2)
self.imageVC?.cameraViewTransform = self.imageVC!.cameraViewTransform.scaledBy(x: scale, y: scale)
self.imageVC?.view.frame = CGRect(x: 0, y: 0, width: screenSize.width, height: screenSize.height)
self.view.addSubview(self.imageVC!.view)
self.view.sendSubviewToBack(self.imageVC!.view)
}
}
摄像头视图也将全屏显示(其他答案无法修正字母框视图)我已投票支持您的答案。它正在做我想做的事情,但我需要取消过视图。如何从CMSampleBuffer录制电影?如何在同一代码中归档全屏cemara视图?然后如何从该图像选择器获取捕获图像路径?.takePicture()在单独的视图中显示有方法更改预览fps吗?与slo mo预览一样,slo mo预览比常规视频预览快得多。单击我添加在该视图顶部的按钮,我可以捕获图像。您应该能够使用CoreGraphics处理此问题。请看:下面的内容太棒了。在电话里看起来不错。但是,如何控制捕获的图像?注意,我已将上述内容添加为子视图,而不是通过IB