在应用程序 (Swift 3) 的相机视图上添加对象而不是在相机视图下?
Adding objects over camera view in app (Swift 3) not under camera view?
我在由红色圆圈组成的相机视图上有一个叠加层,存储在 Assets.xcasset ImgOverlay 占位符中,并且相机视图(预览)出现在叠加层的后面或下面。没关系。应该如此。
当我 运行 iPhone 上的应用程序时,叠加层会正常显示。参见图 1
但我也绘制了一个蓝色圆圈,它在相机视图下方,只有在相机视图丢失时才会出现。也就是说,已关闭,或在模拟器上 运行。请参见下面的 Img.2。
图 1. 相机视图上方的红色圆圈,iPhone
图 2. 红色圆圈包括在模拟器中绘制的蓝色圆圈
我到目前为止的代码在这里。我做错了什么,但看不到。我需要 iPhone 中可见的蓝色圆圈,而不仅仅是在模拟器中。我正在尝试绘制所有圆圈,因此我可以放弃 image.png 类型文件中的红色圆圈。我更喜欢在任何设备上绘制圆圈以获得更高的准确性,并显示它们而不是红色圆圈,然后保存圆圈和相机视图的合成图像。我还没有设法在保存时组合图像,但第一步是让 iPhone 上的蓝色圆圈可见......
所以它几乎完全正常工作。我看不出我做错了什么?
ViewController.swift
import UIKit
import AVFoundation
import Foundation
class ViewController: UIViewController {
@IBOutlet weak var navigationBar: UINavigationBar!
@IBOutlet weak var imgOverlay: UIImageView!
@IBOutlet weak var btnCapture: UIButton!
@IBOutlet weak var shapeLayer: UIView!
let captureSession = AVCaptureSession()
let stillImageOutput = AVCaptureStillImageOutput()
var previewLayer : AVCaptureVideoPreviewLayer?
//var shapeLayer : CALayer?
// If we find a device we'll store it here for later use
var captureDevice : AVCaptureDevice?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//=======================
let midX = self.view.bounds.midX
let midY = self.view.bounds.midY
let circlePath = UIBezierPath(arcCenter: CGPoint(x: midX,y: midY), radius: CGFloat(20), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
//change the fill color
shapeLayer.fillColor = UIColor.clear.cgColor
//you can change the stroke color
shapeLayer.strokeColor = UIColor.blue.cgColor
//you can change the line width
shapeLayer.lineWidth = 2.5
view.layer.addSublayer(shapeLayer)
print("Shape layer drawn")
//=====================
captureSession.sessionPreset = AVCaptureSessionPresetHigh
if let devices = AVCaptureDevice.devices() as? [AVCaptureDevice] {
// Loop through all the capture devices on this phone
for device in devices {
// Make sure this particular device supports video
if (device.hasMediaType(AVMediaTypeVideo)) {
// Finally check the position and confirm we've got the back camera
if(device.position == AVCaptureDevicePosition.back) {
captureDevice = device
if captureDevice != nil {
print("Capture device found")
beginSession()
}
}
}
}
}
}
@IBAction func actionCameraCapture(_ sender: AnyObject) {
print("Camera button pressed")
saveToCamera()
}
func beginSession() {
do {
try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice))
stillImageOutput.outputSettings = [AVVideoCodecKey:AVVideoCodecJPEG]
if captureSession.canAddOutput(stillImageOutput) {
captureSession.addOutput(stillImageOutput)
}
}
catch {
print("error: \(error.localizedDescription)")
}
guard let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) else {
print("no preview layer")
return
}
// this is what displays the camera view. But - it's on TOP of the drawn view, and under the overview. ??
self.view.layer.addSublayer(previewLayer)
previewLayer.frame = self.view.layer.frame
captureSession.startRunning()
print("Capture session running")
self.view.addSubview(navigationBar)
self.view.addSubview(imgOverlay)
self.view.addSubview(btnCapture)
}
func saveToCamera() {
if let videoConnection = stillImageOutput.connection(withMediaType: AVMediaTypeVideo) {
stillImageOutput.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (CMSampleBuffer, Error) in
if let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(CMSampleBuffer) {
if let cameraImage = UIImage(data: imageData) {
UIImageWriteToSavedPhotosAlbum(cameraImage, nil, nil, nil)
}
}
})
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
你非常接近...
你有:
@IBOutlet weak var shapeLayer: UIView!
但随后您还创建了一个名为 shapeLayer 的 CAShapeLayer:
let shapeLayer = CAShapeLayer()
您将其添加为 "main" 视图的子层。然后,在主视图 之上添加其他所有内容 ,覆盖 shapeLayer。
在 viewDidLoad() 中,将您的蓝色圆圈绘制部分更改为:
let midX = self.view.bounds.midX
let midY = self.view.bounds.midY
let circlePath = UIBezierPath(arcCenter: CGPoint(x: midX,y: midY), radius: CGFloat(20), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)
let shapeLayerPath = CAShapeLayer()
shapeLayerPath.path = circlePath.cgPath
//change the fill color
shapeLayerPath.fillColor = UIColor.clear.cgColor
//you can change the stroke color
shapeLayerPath.strokeColor = UIColor.blue.cgColor
//you can change the line width
shapeLayerPath.lineWidth = 2.5
// add the blue-circle layer to the shapeLayer ImageView
shapeLayer.layer.addSublayer(shapeLayerPath)
print("Shape layer drawn")
//=====================
然后,在 beginSession() 结束时...
self.view.addSubview(navigationBar)
self.view.addSubview(imgOverlay)
self.view.addSubview(btnCapture)
// shapeLayer ImageView is already a subview created in IB
// but this will bring it to the front
self.view.addSubview(shapeLayer)
// note: since these elements are added as @IBOutlet in IB,
// these could be:
// self.view.bringSubview(toFront: navigationBar)
// self.view.bringSubview(toFront: imgOverlay)
// self.view.bringSubview(toFront: btnCapture)
// self.view.bringSubview(toFront: shapeLayer)
看看你得到了什么:)
编辑:后续问题移至
我在由红色圆圈组成的相机视图上有一个叠加层,存储在 Assets.xcasset ImgOverlay 占位符中,并且相机视图(预览)出现在叠加层的后面或下面。没关系。应该如此。 当我 运行 iPhone 上的应用程序时,叠加层会正常显示。参见图 1 但我也绘制了一个蓝色圆圈,它在相机视图下方,只有在相机视图丢失时才会出现。也就是说,已关闭,或在模拟器上 运行。请参见下面的 Img.2。
图 1. 相机视图上方的红色圆圈,iPhone
图 2. 红色圆圈包括在模拟器中绘制的蓝色圆圈
我到目前为止的代码在这里。我做错了什么,但看不到。我需要 iPhone 中可见的蓝色圆圈,而不仅仅是在模拟器中。我正在尝试绘制所有圆圈,因此我可以放弃 image.png 类型文件中的红色圆圈。我更喜欢在任何设备上绘制圆圈以获得更高的准确性,并显示它们而不是红色圆圈,然后保存圆圈和相机视图的合成图像。我还没有设法在保存时组合图像,但第一步是让 iPhone 上的蓝色圆圈可见......
所以它几乎完全正常工作。我看不出我做错了什么?
ViewController.swift
import UIKit
import AVFoundation
import Foundation
class ViewController: UIViewController {
@IBOutlet weak var navigationBar: UINavigationBar!
@IBOutlet weak var imgOverlay: UIImageView!
@IBOutlet weak var btnCapture: UIButton!
@IBOutlet weak var shapeLayer: UIView!
let captureSession = AVCaptureSession()
let stillImageOutput = AVCaptureStillImageOutput()
var previewLayer : AVCaptureVideoPreviewLayer?
//var shapeLayer : CALayer?
// If we find a device we'll store it here for later use
var captureDevice : AVCaptureDevice?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
//=======================
let midX = self.view.bounds.midX
let midY = self.view.bounds.midY
let circlePath = UIBezierPath(arcCenter: CGPoint(x: midX,y: midY), radius: CGFloat(20), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
//change the fill color
shapeLayer.fillColor = UIColor.clear.cgColor
//you can change the stroke color
shapeLayer.strokeColor = UIColor.blue.cgColor
//you can change the line width
shapeLayer.lineWidth = 2.5
view.layer.addSublayer(shapeLayer)
print("Shape layer drawn")
//=====================
captureSession.sessionPreset = AVCaptureSessionPresetHigh
if let devices = AVCaptureDevice.devices() as? [AVCaptureDevice] {
// Loop through all the capture devices on this phone
for device in devices {
// Make sure this particular device supports video
if (device.hasMediaType(AVMediaTypeVideo)) {
// Finally check the position and confirm we've got the back camera
if(device.position == AVCaptureDevicePosition.back) {
captureDevice = device
if captureDevice != nil {
print("Capture device found")
beginSession()
}
}
}
}
}
}
@IBAction func actionCameraCapture(_ sender: AnyObject) {
print("Camera button pressed")
saveToCamera()
}
func beginSession() {
do {
try captureSession.addInput(AVCaptureDeviceInput(device: captureDevice))
stillImageOutput.outputSettings = [AVVideoCodecKey:AVVideoCodecJPEG]
if captureSession.canAddOutput(stillImageOutput) {
captureSession.addOutput(stillImageOutput)
}
}
catch {
print("error: \(error.localizedDescription)")
}
guard let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) else {
print("no preview layer")
return
}
// this is what displays the camera view. But - it's on TOP of the drawn view, and under the overview. ??
self.view.layer.addSublayer(previewLayer)
previewLayer.frame = self.view.layer.frame
captureSession.startRunning()
print("Capture session running")
self.view.addSubview(navigationBar)
self.view.addSubview(imgOverlay)
self.view.addSubview(btnCapture)
}
func saveToCamera() {
if let videoConnection = stillImageOutput.connection(withMediaType: AVMediaTypeVideo) {
stillImageOutput.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (CMSampleBuffer, Error) in
if let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(CMSampleBuffer) {
if let cameraImage = UIImage(data: imageData) {
UIImageWriteToSavedPhotosAlbum(cameraImage, nil, nil, nil)
}
}
})
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
你非常接近...
你有:
@IBOutlet weak var shapeLayer: UIView!
但随后您还创建了一个名为 shapeLayer 的 CAShapeLayer:
let shapeLayer = CAShapeLayer()
您将其添加为 "main" 视图的子层。然后,在主视图 之上添加其他所有内容 ,覆盖 shapeLayer。
在 viewDidLoad() 中,将您的蓝色圆圈绘制部分更改为:
let midX = self.view.bounds.midX
let midY = self.view.bounds.midY
let circlePath = UIBezierPath(arcCenter: CGPoint(x: midX,y: midY), radius: CGFloat(20), startAngle: CGFloat(0), endAngle:CGFloat(M_PI * 2), clockwise: true)
let shapeLayerPath = CAShapeLayer()
shapeLayerPath.path = circlePath.cgPath
//change the fill color
shapeLayerPath.fillColor = UIColor.clear.cgColor
//you can change the stroke color
shapeLayerPath.strokeColor = UIColor.blue.cgColor
//you can change the line width
shapeLayerPath.lineWidth = 2.5
// add the blue-circle layer to the shapeLayer ImageView
shapeLayer.layer.addSublayer(shapeLayerPath)
print("Shape layer drawn")
//=====================
然后,在 beginSession() 结束时...
self.view.addSubview(navigationBar)
self.view.addSubview(imgOverlay)
self.view.addSubview(btnCapture)
// shapeLayer ImageView is already a subview created in IB
// but this will bring it to the front
self.view.addSubview(shapeLayer)
// note: since these elements are added as @IBOutlet in IB,
// these could be:
// self.view.bringSubview(toFront: navigationBar)
// self.view.bringSubview(toFront: imgOverlay)
// self.view.bringSubview(toFront: btnCapture)
// self.view.bringSubview(toFront: shapeLayer)
看看你得到了什么:)
编辑:后续问题移至