I have a need for a simple QR Code class that I can re-use. I have created the class and it works, however manually setting the size constraints is not desired because it needs to adjust its size based on the DPI of the device. Here in this minimal example, I just use 100 as the sizing calculation code is not relevant (set to 50 in IB). Also I will have multiple QR Codes in different positions, which I will manage their positioning by IB. But at least I hope to be able to set the width and height constraints in code.
The below code shows a QR code, in the right size (set at runtime), but when the constraints are set to horizontally and vertically center it, it does not. Again, I don't want the size constraints in the IB, but I do want the position constraints in the IB
import Foundation
import UIKit
@IBDesignable class QrCodeView: UIImageView {
var content:String = "test" {
didSet {
generateCode(content)
}
}
lazy var filter = CIFilter(name: "CIQRCodeGenerator")
lazy var imageView = UIImageView()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override func layoutSubviews() {
super.layoutSubviews()
imageView.frame = CGRect(x:0, y:0, width:100, height:100)
frame = CGRect(x:frame.origin.x, y:frame.origin.y, width:100, height:100)
}
func setup() {
//translatesAutoresizingMaskIntoConstraints = false
generateCode(content)
addSubview(imageView)
layoutIfNeeded()
}
func generateCode(_ string: String) {
guard let filter = filter,
let data = string.data(using: .isoLatin1, allowLossyConversion: false) else {
return
}
filter.setValue(data, forKey: "inputMessage")
guard let ciImage = filter.outputImage else {
return
}
let transform = CGAffineTransform(scaleX: 10, y: 10)
let scaled = UIImage(ciImage: ciImage.transformed(by: transform))
imageView.image = scaled
}
}
I believe you're making this more complicated than need be...
Let's start with a simple
@IBDesignable UIImageViewsubclass.Start with a new project and add this code:
Now, in Storyboard, add a
UIImageViewto a view controller. Set its custom class toMyImageViewand set Horizontal and Vertical Center constraints.The image view should automatically size itself to
100 x 100, centered in the view with a green background (we're just setting the background so we can see it):Run the app, and you should see the same thing.
Now, add it as an
@IBOutletto a view controller:Run the app, and you will see a centered green image view, but now it will be
300 x 300points instead of100 x 100.The rest of your task is pretty much adding code to set this custom class's
.imageproperty once you've rendered the QRCode image.Here's the custom class:
In Storyboard / IB:
And here's an example view controller:
Edit
Here's a modified
QRCodeViewclass that will size itself to a (physical) 15x15 mm image.I used
DeviceKitfrom https://github.com/devicekit/DeviceKit to get the current device'sppi. See the comment to replace it with your own (assuming you are already using something else).When this class is instantiated, it will:
The
QRCodeView(subclass ofUIImageView) needs only position constraints... so you can use Top + Leading, Top + Trailing, Center X & Y, Bottom + CenterX, etc, etc.