iOS 扫一扫功能
作者:互联网
class TestScanView: UIView {
///扫描结果
var scanBlock:((AVMetadataObject.ObjectType,String)->())?
let middle_width = kScreenWidth * 0.8
let top_height = kScreenHeight * 0.25
let center_line_height:CGFloat = 10
lazy var centerLineView: UIImageView = {
let view = UIImageView(frame: CGRect(x: (kScreenWidth - middle_width)/2, y: top_height, width: middle_width, height: center_line_height * middle_width/267))
view.image = UIImage(named: "scan_center_line")
return view
}()
lazy var blackMaskView: UIImageView = {
let view = UIImageView(frame: kWindow.bounds)
view.image = maskViewImage(maskRect: kWindow.bounds, clearRect: CGRect(x: (kScreenWidth - middle_width)/2, y: top_height, width: middle_width, height: middle_width))
return view
}()
lazy var borderView: UIImageView = {
let view = UIImageView(frame:CGRect(x: (kScreenWidth - middle_width)/2, y: top_height, width: middle_width, height: middle_width))
view.image = UIImage(named: "scan_border_line")
return view
}()
lazy var device: AVCaptureDevice? = {
let d = AVCaptureDevice.default(for: .video)
return d
}()
lazy var scannerSession: AVCaptureSession = {
let session = AVCaptureSession()
guard device != nil else {
kWindow.makeToast("相机不可用", duration: 1.5, position: .center)
return session
}
let input = try? AVCaptureDeviceInput(device: device!)
let output = AVCaptureMetadataOutput()
output.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
//设置扫描的区域
NotificationCenter.default.addObserver(forName: Notification.Name.AVCaptureInputPortFormatDescriptionDidChange, object: nil, queue: OperationQueue.current) { [self] _ in
output.rectOfInterest = previewLayer.metadataOutputRectConverted(fromLayerRect: CGRect(x: (kScreenWidth - middle_width)/2, y: top_height, width: middle_width, height: middle_width))
}
if session.canSetSessionPreset(.hd1280x720) {
session.sessionPreset = .hd1280x720
}
else if session.canSetSessionPreset(.hd1920x1080) {
session.sessionPreset = .hd1920x1080
}
else if session.canSetSessionPreset(.hd4K3840x2160) {
session.sessionPreset = .hd4K3840x2160
}
else {
session.sessionPreset = .photo
}
guard input != nil else {
kWindow.makeToast("相机不可用", duration: 1.5, position: .center)
return session
}
if session.canAddInput(input!) {
session.addInput(input!)
}
if session.canAddOutput(output) {
session.addOutput(output)
}
output.metadataObjectTypes = [.qr,.code128,.ean8,.upce,.code39,.pdf417,.aztec,.code93,.ean13,.code39Mod43]
return session
}()
lazy var previewLayer: AVCaptureVideoPreviewLayer = {
let layer = AVCaptureVideoPreviewLayer(session: scannerSession)
layer.videoGravity = .resizeAspectFill
layer.frame = bounds
return layer
}()
///判断centerLineView是往下走还是往上走
var isGoDown = true
var timer:Timer?
/// centerLineView实时的位置增量
var updateMeasure = 0
override init(frame: CGRect) {
super.init(frame: frame)
layer.insertSublayer(previewLayer, at: 0)
addSubview(blackMaskView)
addSubview(borderView)
addSubview(centerLineView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK: 自动去聚焦
func autoFocus() {
guard device != nil else {
return
}
scannerSession.beginConfiguration()
try? device!.lockForConfiguration()
if device!.isFocusModeSupported(.autoFocus) {
device!.focusMode = .autoFocus
}
if device!.isExposureModeSupported(.autoExpose) {
device!.exposureMode = .autoExpose
}
device!.unlockForConfiguration()
scannerSession.commitConfiguration()
}
func maskViewImage(maskRect:CGRect,clearRect:CGRect) -> UIImage? {
UIGraphicsBeginImageContext(maskRect.size)
let ctx = UIGraphicsGetCurrentContext()!
ctx.setFillColor(red: 0,green: 0,blue: 0,alpha: 0.6)
var drawRect = maskRect
ctx.fill(drawRect) //draw the transparent layer
drawRect = clearRect
ctx.clear(drawRect) //clear the center rect of the layer
let returnImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return returnImage
}
//MARK: 开启扫描
func startSession() {
if timer != nil {
timer?.invalidate()
timer = nil
}
timer = Timer.scheduledTimer(timeInterval: 0.02, target: self, selector: #selector(animation), userInfo: nil, repeats: true)
scannerSession.startRunning()
}
//MARK: 关闭扫描
func stopSession() {
timer?.invalidate()
timer = nil
flashSettingAction(isOpen: false)
scannerSession.stopRunning()
}
//MARK: 横线移动
@objc func animation() {
let originalX = (kScreenWidth - middle_width)/2
if isGoDown {
updateMeasure += 1
centerLineView.frame = CGRect(x: originalX, y: top_height + 2 * CGFloat(updateMeasure), width: middle_width, height: center_line_height * middle_width/267)
if 2 * CGFloat(updateMeasure) > middle_width - center_line_height * middle_width/267 {
isGoDown = false
}
}
else {
updateMeasure -= 1
centerLineView.frame = CGRect(x: originalX, y: top_height + 2 * CGFloat(updateMeasure), width: middle_width, height: center_line_height * middle_width/267)
if updateMeasure == 0 {
isGoDown = true
}
}
autoFocus()
}
//MARK: 开启关闭闪光灯
func flashSettingAction(isOpen:Bool) {
guard device != nil else {
return
}
if device!.hasTorch {
try? device!.lockForConfiguration()
device!.torchMode = isOpen ? .on : .off
device!.unlockForConfiguration()
}
}
}
extension TestScanView: AVCaptureMetadataOutputObjectsDelegate {
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
print(metadataObjects)
if metadataObjects.count > 0 {
stopSession()
if let scanResult = metadataObjects.first as? AVMetadataMachineReadableCodeObject {
if scanResult.stringValue != nil {
print("扫描类型",scanResult.type)
print("扫描结果",scanResult.stringValue!)
scanBlock?(scanResult.type,scanResult.stringValue!)
}
else {
startSession()
}
}
else {
startSession()
}
}
else {
startSession()
}
}
}
标签:功能,middle,扫一扫,iOS,height,width,session,let,device 来源: https://blog.csdn.net/weixin_43259805/article/details/122410646