parent
dff48390b3
commit
a8b4576243
|
@ -1,5 +1,9 @@
|
||||||
# Change log
|
# Change log
|
||||||
|
|
||||||
|
## Version 10.0.0
|
||||||
|
|
||||||
|
- [ADD] Allowing the scan area configuration (#157 #106)
|
||||||
|
|
||||||
## [Version 9.0.0](https://github.com/yannickl/QRCodeReader.swift/releases/tag/9.0.0)
|
## [Version 9.0.0](https://github.com/yannickl/QRCodeReader.swift/releases/tag/9.0.0)
|
||||||
Release on 2018-09-19
|
Release on 2018-09-19
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,11 @@ import UIKit
|
||||||
class ViewController: UIViewController, QRCodeReaderViewControllerDelegate {
|
class ViewController: UIViewController, QRCodeReaderViewControllerDelegate {
|
||||||
@IBOutlet weak var previewView: QRCodeReaderView! {
|
@IBOutlet weak var previewView: QRCodeReaderView! {
|
||||||
didSet {
|
didSet {
|
||||||
previewView.setupComponents(showCancelButton: false, showSwitchCameraButton: false, showTorchButton: false, showOverlayView: true, reader: reader)
|
previewView.setupComponents(with: QRCodeReaderViewControllerBuilder {
|
||||||
|
$0.reader = reader
|
||||||
|
$0.showTorchButton = false
|
||||||
|
$0.showSwitchCameraButton = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lazy var reader: QRCodeReader = QRCodeReader()
|
lazy var reader: QRCodeReader = QRCodeReader()
|
||||||
|
@ -39,6 +43,7 @@ class ViewController: UIViewController, QRCodeReaderViewControllerDelegate {
|
||||||
$0.reader = QRCodeReader(metadataObjectTypes: [.qr], captureDevicePosition: .back)
|
$0.reader = QRCodeReader(metadataObjectTypes: [.qr], captureDevicePosition: .back)
|
||||||
$0.showTorchButton = true
|
$0.showTorchButton = true
|
||||||
$0.preferredStatusBarStyle = .lightContent
|
$0.preferredStatusBarStyle = .lightContent
|
||||||
|
$0.rectOfInterest = CGRect(x: 0.15, y: 0.15, width: 0.7, height: 0.7)
|
||||||
|
|
||||||
$0.reader.stopScanningWhenCodeIsFound = false
|
$0.reader.stopScanningWhenCodeIsFound = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,8 @@ public final class QRCodeReader: NSObject, AVCaptureMetadataOutputObjectsDelegat
|
||||||
private let sessionQueue = DispatchQueue(label: "session queue")
|
private let sessionQueue = DispatchQueue(label: "session queue")
|
||||||
private let metadataObjectsQueue = DispatchQueue(label: "com.yannickloriot.qr", attributes: [], target: nil)
|
private let metadataObjectsQueue = DispatchQueue(label: "com.yannickloriot.qr", attributes: [], target: nil)
|
||||||
|
|
||||||
var defaultDevice: AVCaptureDevice? = AVCaptureDevice.default(for: .video)
|
let defaultDevice: AVCaptureDevice? = AVCaptureDevice.default(for: .video)
|
||||||
var frontDevice: AVCaptureDevice? = {
|
let frontDevice: AVCaptureDevice? = {
|
||||||
if #available(iOS 10, *) {
|
if #available(iOS 10, *) {
|
||||||
return AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .front)
|
return AVCaptureDevice.default(.builtInWideAngleCamera, for: AVMediaType.video, position: .front)
|
||||||
}
|
}
|
||||||
|
@ -67,8 +67,8 @@ public final class QRCodeReader: NSObject, AVCaptureMetadataOutputObjectsDelegat
|
||||||
return nil
|
return nil
|
||||||
}()
|
}()
|
||||||
|
|
||||||
public var metadataOutput = AVCaptureMetadataOutput()
|
let session = AVCaptureSession()
|
||||||
var session = AVCaptureSession()
|
let metadataOutput = AVCaptureMetadataOutput()
|
||||||
|
|
||||||
weak var lifeCycleDelegate: QRCodeReaderLifeCycleDelegate?
|
weak var lifeCycleDelegate: QRCodeReaderLifeCycleDelegate?
|
||||||
|
|
||||||
|
|
|
@ -73,16 +73,16 @@ final public class QRCodeReaderView: UIView, QRCodeReaderDisplayable {
|
||||||
|
|
||||||
private weak var reader: QRCodeReader?
|
private weak var reader: QRCodeReader?
|
||||||
|
|
||||||
public func setupComponents(showCancelButton: Bool, showSwitchCameraButton: Bool, showTorchButton: Bool, showOverlayView: Bool, reader: QRCodeReader?) {
|
public func setupComponents(with builder: QRCodeReaderViewControllerBuilder) {
|
||||||
self.reader = reader
|
self.reader = builder.reader
|
||||||
reader?.lifeCycleDelegate = self
|
reader?.lifeCycleDelegate = self
|
||||||
|
|
||||||
addComponents()
|
addComponents()
|
||||||
|
|
||||||
cancelButton?.isHidden = !showCancelButton
|
cancelButton?.isHidden = !builder.showCancelButton
|
||||||
switchCameraButton?.isHidden = !showSwitchCameraButton
|
switchCameraButton?.isHidden = !builder.showSwitchCameraButton
|
||||||
toggleTorchButton?.isHidden = !showTorchButton
|
toggleTorchButton?.isHidden = !builder.showTorchButton
|
||||||
overlayView?.isHidden = !showOverlayView
|
overlayView?.isHidden = !builder.showOverlayView
|
||||||
|
|
||||||
guard let cb = cancelButton, let scb = switchCameraButton, let ttb = toggleTorchButton, let ov = overlayView else { return }
|
guard let cb = cancelButton, let scb = switchCameraButton, let ttb = toggleTorchButton, let ov = overlayView else { return }
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ final public class QRCodeReaderView: UIView, QRCodeReaderDisplayable {
|
||||||
|
|
||||||
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[cv]|", options: [], metrics: nil, views: views))
|
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[cv]|", options: [], metrics: nil, views: views))
|
||||||
|
|
||||||
if showCancelButton {
|
if builder.showCancelButton {
|
||||||
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[cv][cb(40)]|", options: [], metrics: nil, views: views))
|
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[cv][cb(40)]|", options: [], metrics: nil, views: views))
|
||||||
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[cb]-|", options: [], metrics: nil, views: views))
|
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[cb]-|", options: [], metrics: nil, views: views))
|
||||||
}
|
}
|
||||||
|
@ -98,12 +98,12 @@ final public class QRCodeReaderView: UIView, QRCodeReaderDisplayable {
|
||||||
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[cv]|", options: [], metrics: nil, views: views))
|
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[cv]|", options: [], metrics: nil, views: views))
|
||||||
}
|
}
|
||||||
|
|
||||||
if showSwitchCameraButton {
|
if builder.showSwitchCameraButton {
|
||||||
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[scb(50)]", options: [], metrics: nil, views: views))
|
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[scb(50)]", options: [], metrics: nil, views: views))
|
||||||
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[scb(70)]|", options: [], metrics: nil, views: views))
|
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:[scb(70)]|", options: [], metrics: nil, views: views))
|
||||||
}
|
}
|
||||||
|
|
||||||
if showTorchButton {
|
if builder.showTorchButton {
|
||||||
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[ttb(50)]", options: [], metrics: nil, views: views))
|
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[ttb(50)]", options: [], metrics: nil, views: views))
|
||||||
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[ttb(70)]", options: [], metrics: nil, views: views))
|
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[ttb(70)]", options: [], metrics: nil, views: views))
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,10 @@ final public class QRCodeReaderView: UIView, QRCodeReaderDisplayable {
|
||||||
for attribute in Array<NSLayoutConstraint.Attribute>([.left, .top, .right, .bottom]) {
|
for attribute in Array<NSLayoutConstraint.Attribute>([.left, .top, .right, .bottom]) {
|
||||||
addConstraint(NSLayoutConstraint(item: ov, attribute: attribute, relatedBy: .equal, toItem: cameraView, attribute: attribute, multiplier: 1, constant: 0))
|
addConstraint(NSLayoutConstraint(item: ov, attribute: attribute, relatedBy: .equal, toItem: cameraView, attribute: attribute, multiplier: 1, constant: 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let readerOverlayView = overlayView as? ReaderOverlayView {
|
||||||
|
readerOverlayView.rectOfInterest = builder.rectOfInterest
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func layoutSubviews() {
|
public override func layoutSubviews() {
|
||||||
|
|
|
@ -47,15 +47,11 @@ public protocol QRCodeReaderDisplayable {
|
||||||
func setNeedsUpdateOrientation()
|
func setNeedsUpdateOrientation()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Method called by the container to allows you to layout your view properly using the given flags.
|
Method called by the container to allows you to layout your view properly using the QR code reader builder.
|
||||||
|
|
||||||
- Parameter showCancelButton: Flag to know whether you should display the cancel button.
|
- Parameter builder: A QR code reader builder.
|
||||||
- Parameter showSwitchCameraButton: Flag to know whether you should display the switch camera button.
|
|
||||||
- Parameter showTorchButton: Flag to know whether you should display the toggle torch button.
|
|
||||||
- Parameter showOverlayView: Flag to know whether you should display the overlay.
|
|
||||||
- Parameter reader: A reference to the code reader.
|
|
||||||
*/
|
*/
|
||||||
func setupComponents(showCancelButton: Bool, showSwitchCameraButton: Bool, showTorchButton: Bool, showOverlayView: Bool, reader: QRCodeReader?)
|
func setupComponents(with builder: QRCodeReaderViewControllerBuilder)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The `QRCodeReaderContainer` structure embed the view displayed by the controller. The embeded view must be conform to the `QRCodeReaderDisplayable` protocol.
|
/// The `QRCodeReaderContainer` structure embed the view displayed by the controller. The embeded view must be conform to the `QRCodeReaderDisplayable` protocol.
|
||||||
|
@ -75,7 +71,7 @@ public struct QRCodeReaderContainer {
|
||||||
|
|
||||||
// MARK: - Convenience Methods
|
// MARK: - Convenience Methods
|
||||||
|
|
||||||
func setupComponents(showCancelButton: Bool, showSwitchCameraButton: Bool, showTorchButton: Bool, showOverlayView: Bool, reader: QRCodeReader? = nil) {
|
func setupComponents(with builder: QRCodeReaderViewControllerBuilder) {
|
||||||
displayable.setupComponents(showCancelButton: showCancelButton, showSwitchCameraButton: showSwitchCameraButton, showTorchButton: showTorchButton, showOverlayView: showOverlayView, reader: reader)
|
displayable.setupComponents(with: builder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,16 +29,12 @@ import AVFoundation
|
||||||
|
|
||||||
/// Convenient controller to display a view to scan/read 1D or 2D bar codes like the QRCodes. It is based on the `AVFoundation` framework from Apple. It aims to replace ZXing or ZBar for iOS 7 and over.
|
/// Convenient controller to display a view to scan/read 1D or 2D bar codes like the QRCodes. It is based on the `AVFoundation` framework from Apple. It aims to replace ZXing or ZBar for iOS 7 and over.
|
||||||
public class QRCodeReaderViewController: UIViewController {
|
public class QRCodeReaderViewController: UIViewController {
|
||||||
/// The code reader object used to scan the bar code.
|
private let builder: QRCodeReaderViewControllerBuilder
|
||||||
public let codeReader: QRCodeReader
|
|
||||||
|
|
||||||
let readerView: QRCodeReaderContainer
|
/// The code reader object used to scan the bar code.
|
||||||
let startScanningAtLoad: Bool
|
public var codeReader: QRCodeReader {
|
||||||
let showCancelButton: Bool
|
return builder.reader
|
||||||
let showSwitchCameraButton: Bool
|
}
|
||||||
let showTorchButton: Bool
|
|
||||||
let showOverlayView: Bool
|
|
||||||
let customPreferredStatusBarStyle: UIStatusBarStyle?
|
|
||||||
|
|
||||||
// MARK: - Managing the Callback Responders
|
// MARK: - Managing the Callback Responders
|
||||||
|
|
||||||
|
@ -62,14 +58,7 @@ public class QRCodeReaderViewController: UIViewController {
|
||||||
- parameter builder: A QRCodeViewController builder object.
|
- parameter builder: A QRCodeViewController builder object.
|
||||||
*/
|
*/
|
||||||
required public init(builder: QRCodeReaderViewControllerBuilder) {
|
required public init(builder: QRCodeReaderViewControllerBuilder) {
|
||||||
readerView = builder.readerView
|
self.builder = builder
|
||||||
startScanningAtLoad = builder.startScanningAtLoad
|
|
||||||
codeReader = builder.reader
|
|
||||||
showCancelButton = builder.showCancelButton
|
|
||||||
showSwitchCameraButton = builder.showSwitchCameraButton
|
|
||||||
showTorchButton = builder.showTorchButton
|
|
||||||
showOverlayView = builder.showOverlayView
|
|
||||||
customPreferredStatusBarStyle = builder.preferredStatusBarStyle
|
|
||||||
|
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
|
||||||
|
@ -77,7 +66,7 @@ public class QRCodeReaderViewController: UIViewController {
|
||||||
|
|
||||||
codeReader.didFindCode = { [weak self] resultAsObject in
|
codeReader.didFindCode = { [weak self] resultAsObject in
|
||||||
if let weakSelf = self {
|
if let weakSelf = self {
|
||||||
if let qrv = weakSelf.readerView.displayable as? QRCodeReaderView {
|
if let qrv = builder.readerView.displayable as? QRCodeReaderView {
|
||||||
qrv.addGreenBorder()
|
qrv.addGreenBorder()
|
||||||
}
|
}
|
||||||
weakSelf.completionBlock?(resultAsObject)
|
weakSelf.completionBlock?(resultAsObject)
|
||||||
|
@ -85,11 +74,9 @@ public class QRCodeReaderViewController: UIViewController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
codeReader.didFailDecoding = { [weak self] in
|
codeReader.didFailDecoding = {
|
||||||
if let weakSelf = self {
|
if let qrv = builder.readerView.displayable as? QRCodeReaderView {
|
||||||
if let qrv = weakSelf.readerView.displayable as? QRCodeReaderView {
|
qrv.addRedBorder()
|
||||||
qrv.addRedBorder()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,14 +84,7 @@ public class QRCodeReaderViewController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
required public init?(coder aDecoder: NSCoder) {
|
required public init?(coder aDecoder: NSCoder) {
|
||||||
codeReader = QRCodeReader()
|
self.builder = QRCodeReaderViewControllerBuilder()
|
||||||
readerView = QRCodeReaderContainer(displayable: QRCodeReaderView())
|
|
||||||
startScanningAtLoad = false
|
|
||||||
showCancelButton = false
|
|
||||||
showTorchButton = false
|
|
||||||
showSwitchCameraButton = false
|
|
||||||
showOverlayView = false
|
|
||||||
customPreferredStatusBarStyle = nil
|
|
||||||
|
|
||||||
super.init(coder: aDecoder)
|
super.init(coder: aDecoder)
|
||||||
}
|
}
|
||||||
|
@ -114,8 +94,8 @@ public class QRCodeReaderViewController: UIViewController {
|
||||||
override public func viewWillAppear(_ animated: Bool) {
|
override public func viewWillAppear(_ animated: Bool) {
|
||||||
super.viewWillAppear(animated)
|
super.viewWillAppear(animated)
|
||||||
|
|
||||||
if startScanningAtLoad {
|
if builder.startScanningAtLoad {
|
||||||
readerView.displayable.setNeedsUpdateOrientation()
|
builder.readerView.displayable.setNeedsUpdateOrientation()
|
||||||
|
|
||||||
startScanning()
|
startScanning()
|
||||||
}
|
}
|
||||||
|
@ -134,38 +114,35 @@ public class QRCodeReaderViewController: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public override var preferredStatusBarStyle: UIStatusBarStyle {
|
public override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||||
return customPreferredStatusBarStyle ?? super.preferredStatusBarStyle
|
return builder.preferredStatusBarStyle ?? super.preferredStatusBarStyle
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Initializing the AV Components
|
// MARK: - Initializing the AV Components
|
||||||
|
|
||||||
private func setupUIComponentsWithCancelButtonTitle(_ cancelButtonTitle: String) {
|
private func setupUIComponentsWithCancelButtonTitle(_ cancelButtonTitle: String) {
|
||||||
view.addSubview(readerView.view)
|
view.addSubview(builder.readerView.view)
|
||||||
|
|
||||||
let sscb = showSwitchCameraButton && codeReader.hasFrontDevice
|
builder.readerView.view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
let stb = showTorchButton && codeReader.isTorchAvailable
|
builder.readerView.setupComponents(with: builder)
|
||||||
|
|
||||||
readerView.view.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
readerView.setupComponents(showCancelButton: showCancelButton, showSwitchCameraButton: sscb, showTorchButton: stb, showOverlayView: showOverlayView, reader: codeReader)
|
|
||||||
|
|
||||||
// Setup action methods
|
// Setup action methods
|
||||||
|
|
||||||
readerView.displayable.switchCameraButton?.addTarget(self, action: #selector(switchCameraAction), for: .touchUpInside)
|
builder.readerView.displayable.switchCameraButton?.addTarget(self, action: #selector(switchCameraAction), for: .touchUpInside)
|
||||||
readerView.displayable.toggleTorchButton?.addTarget(self, action: #selector(toggleTorchAction), for: .touchUpInside)
|
builder.readerView.displayable.toggleTorchButton?.addTarget(self, action: #selector(toggleTorchAction), for: .touchUpInside)
|
||||||
readerView.displayable.cancelButton?.setTitle(cancelButtonTitle, for: .normal)
|
builder.readerView.displayable.cancelButton?.setTitle(cancelButtonTitle, for: .normal)
|
||||||
readerView.displayable.cancelButton?.addTarget(self, action: #selector(cancelAction), for: .touchUpInside)
|
builder.readerView.displayable.cancelButton?.addTarget(self, action: #selector(cancelAction), for: .touchUpInside)
|
||||||
|
|
||||||
// Setup constraints
|
// Setup constraints
|
||||||
|
|
||||||
for attribute in [.left, .top, .right] as [NSLayoutConstraint.Attribute] {
|
for attribute in [.left, .top, .right] as [NSLayoutConstraint.Attribute] {
|
||||||
NSLayoutConstraint(item: readerView.view, attribute: attribute, relatedBy: .equal, toItem: view, attribute: attribute, multiplier: 1, constant: 0).isActive = true
|
NSLayoutConstraint(item: builder.readerView.view, attribute: attribute, relatedBy: .equal, toItem: view, attribute: attribute, multiplier: 1, constant: 0).isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if #available(iOS 11.0, *) {
|
if #available(iOS 11.0, *) {
|
||||||
view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: readerView.view.bottomAnchor).isActive = true
|
view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: builder.readerView.view.bottomAnchor).isActive = true
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
NSLayoutConstraint(item: readerView.view, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0).isActive = true
|
NSLayoutConstraint(item: builder.readerView.view, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0).isActive = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,12 +68,28 @@ public final class QRCodeReaderViewControllerBuilder {
|
||||||
/**
|
/**
|
||||||
Flag to display the switch camera button.
|
Flag to display the switch camera button.
|
||||||
*/
|
*/
|
||||||
public var showSwitchCameraButton = true
|
public var showSwitchCameraButton: Bool {
|
||||||
|
get {
|
||||||
|
return _showSwitchCameraButton && reader.hasFrontDevice
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
_showSwitchCameraButton = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private var _showSwitchCameraButton: Bool = true
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Flag to display the toggle torch button. If the value is true and there is no torch the button will not be displayed.
|
Flag to display the toggle torch button. If the value is true and there is no torch the button will not be displayed.
|
||||||
*/
|
*/
|
||||||
public var showTorchButton = false
|
public var showTorchButton: Bool {
|
||||||
|
get {
|
||||||
|
return _showTorchButton && reader.isTorchAvailable
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
_showTorchButton = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private var _showTorchButton = true
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Flag to display the guide view.
|
Flag to display the guide view.
|
||||||
|
@ -91,6 +107,22 @@ public final class QRCodeReaderViewControllerBuilder {
|
||||||
*/
|
*/
|
||||||
public var preferredStatusBarStyle: UIStatusBarStyle? = nil
|
public var preferredStatusBarStyle: UIStatusBarStyle? = nil
|
||||||
|
|
||||||
|
/**
|
||||||
|
Specifies a rectangle of interest for limiting the search area for visual metadata.
|
||||||
|
|
||||||
|
The value of this property is a CGRect that determines the receiver's rectangle of interest for each frame of video. The rectangle's origin is top left and is relative to the coordinate space of the device providing the metadata. Specifying a rectOfInterest may improve detection performance for certain types of metadata. The default value of this property is the value CGRectMake(0, 0, 1, 1). Metadata objects whose bounds do not intersect with the rectOfInterest will not be returned.
|
||||||
|
*/
|
||||||
|
public var rectOfInterest: CGRect = CGRect(x: 0, y: 0, width: 1, height: 1) {
|
||||||
|
didSet {
|
||||||
|
reader.metadataOutput.rectOfInterest = CGRect(
|
||||||
|
x: min(max(rectOfInterest.origin.x, 0), 1),
|
||||||
|
y: min(max(rectOfInterest.origin.y, 0), 1),
|
||||||
|
width: min(max(rectOfInterest.width, 0), 1),
|
||||||
|
height: min(max(rectOfInterest.height, 0), 1)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Initializing a Flap View
|
// MARK: - Initializing a Flap View
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -58,24 +58,25 @@ public final class ReaderOverlayView: UIView {
|
||||||
|
|
||||||
var overlayColor: UIColor = UIColor.white {
|
var overlayColor: UIColor = UIColor.white {
|
||||||
didSet {
|
didSet {
|
||||||
self.overlay.strokeColor = overlayColor.cgColor
|
overlay.strokeColor = overlayColor.cgColor
|
||||||
|
|
||||||
self.setNeedsDisplay()
|
setNeedsDisplay()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rectOfInterest: CGRect = CGRect(x: 0, y: 0, width: 1, height: 1) {
|
||||||
|
didSet {
|
||||||
|
setNeedsDisplay()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func draw(_ rect: CGRect) {
|
public override func draw(_ rect: CGRect) {
|
||||||
var innerRect = rect.insetBy(dx: 50, dy: 50)
|
let innerRect = CGRect(
|
||||||
let minSize = min(innerRect.width, innerRect.height)
|
x: rect.width * rectOfInterest.minX,
|
||||||
|
y: rect.height * rectOfInterest.minY,
|
||||||
if innerRect.width != minSize {
|
width: rect.width * rectOfInterest.width,
|
||||||
innerRect.origin.x += (innerRect.width - minSize) / 2
|
height: rect.height * rectOfInterest.height
|
||||||
innerRect.size.width = minSize
|
)
|
||||||
}
|
|
||||||
else if innerRect.height != minSize {
|
|
||||||
innerRect.origin.y += (innerRect.height - minSize) / 2
|
|
||||||
innerRect.size.height = minSize
|
|
||||||
}
|
|
||||||
|
|
||||||
overlay.path = UIBezierPath(roundedRect: innerRect, cornerRadius: 5).cgPath
|
overlay.path = UIBezierPath(roundedRect: innerRect, cornerRadius: 5).cgPath
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue