I created a UIButton subclass that looks like a checkmark.
Here is the class:
import UIKit
@IBDesignable
class CheckedButton: UIButton {
// MARK: - Properties
@IBInspectable var checked: Bool = false {
didSet {
// Toggle the check/uncheck images
updateImage()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
private func setup() {
updateImage()
self.addTarget(self, action: #selector(tapped), for: .touchUpInside)
}
private func updateImage() {
let image = checked ? UIImage(named: "checked") : UIImage(named: "unchecked")
self.setImage(image, for: .normal)
}
/// Called each time the button is tapped, and toggles the checked property
@objc private func tapped() {
checked = !checked
print("New value: \(checked)")
}
}
Since I set the checked
property as @IBInspectable, I see it in IB :
The weird thing is:
default
, it is correctly showing in the storyboardon
or off
inthe inspector, the screen is not updated properly.As the class is marked @IBDesignable, I would expect the button appearance to update in IB according to the value set for this property in the inspector tab. Got a clue?
UIimage(named:) method uses main bundle but Interface Builder load resources in different way.
Try this:
UIImage(named: "checked", in: bundle, compatibleWith: nil)
@IBDesignable
class CheckedButton: UIButton {
// MARK: - Properties
@IBInspectable var checked: Bool = false {
didSet {
// Toggle the check/uncheck images
updateImage()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setup()
}
internal func setup() {
self.addTarget(self, action: #selector(tapped), for: .touchUpInside)
}
private func updateImage() {
let bundle = Bundle(for: CheckedButton.self)
let image = checked ? UIImage(named: "checked", in: bundle, compatibleWith:nil) : UIImage(named: "unchecked", in: bundle, compatibleWith:nil)
self.setBackgroundImage(image, for: .normal)
}
/// Called each time the button is tapped, and toggles the checked property
@objc private func tapped() {
checked = !checked
print("New value: \(checked)")
}