自定义 UIButton @IBDesignable
Custom UIButton @IBDesignable
我创建了一个 UIButton subclass,看起来像一个复选标记。
这是 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)")
}
}
由于我将 checked
属性 设置为 @IBInspectable,所以我在 IB 中看到了它:
奇怪的是:
- 如果我将此 属性 设置为
default
,它会在故事板中正确显示
- 但如果我在检查器中选择
on
或 off
,则屏幕不会正确更新。
由于 class 标记为@IBDesignable,我希望按钮外观在 IB 中根据检查器选项卡中为此 属性 设置的值进行更新。
有线索吗?
我的建议是使用其他自定义函数从资产中获取图像:
extension UIImage {
public static func image(name: String, _ sender: UIView?) -> UIImage? {
#if TARGET_INTERFACE_BUILDER
if let sender = sender {
let bundle = Bundle(for: sender.classForCoder)
return UIImage(named: name, in: bundle, compatibleWith: sender.traitCollection)
} else {
return UIImage(named: name)
}
#else
return UIImage(named: name)
#endif
}
}
以你的例子为例:
private func updateImage() {
let image = checked ? UIImage.image(name: "checked", self) : UIImage(name: "unchecked", self)
setImage(image, for: .normal)
}
此外,UIButton class 已检查状态,您无需创建自己的子项即可使用 class:
let btn = UIButton(type: .custom)
btn.setImage(UIImage.image(name: "unchecked", self), for: .normal)
btn.setImage(UIImage.image(name: "checked", self), for: .selected)
btn.isSelected = true // change button state between checked and unchecked
UIimage(named:) 方法使用主包,但 Interface Builder 以不同的方式加载资源。
试试这个:
UIImage(命名:"checked",在:bundle,兼容: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)")
}
我创建了一个 UIButton subclass,看起来像一个复选标记。
这是 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)")
}
}
由于我将 checked
属性 设置为 @IBInspectable,所以我在 IB 中看到了它:
奇怪的是:
- 如果我将此 属性 设置为
default
,它会在故事板中正确显示
- 但如果我在检查器中选择
on
或off
,则屏幕不会正确更新。
由于 class 标记为@IBDesignable,我希望按钮外观在 IB 中根据检查器选项卡中为此 属性 设置的值进行更新。 有线索吗?
我的建议是使用其他自定义函数从资产中获取图像:
extension UIImage {
public static func image(name: String, _ sender: UIView?) -> UIImage? {
#if TARGET_INTERFACE_BUILDER
if let sender = sender {
let bundle = Bundle(for: sender.classForCoder)
return UIImage(named: name, in: bundle, compatibleWith: sender.traitCollection)
} else {
return UIImage(named: name)
}
#else
return UIImage(named: name)
#endif
}
}
以你的例子为例:
private func updateImage() {
let image = checked ? UIImage.image(name: "checked", self) : UIImage(name: "unchecked", self)
setImage(image, for: .normal)
}
此外,UIButton class 已检查状态,您无需创建自己的子项即可使用 class:
let btn = UIButton(type: .custom)
btn.setImage(UIImage.image(name: "unchecked", self), for: .normal)
btn.setImage(UIImage.image(name: "checked", self), for: .selected)
btn.isSelected = true // change button state between checked and unchecked
UIimage(named:) 方法使用主包,但 Interface Builder 以不同的方式加载资源。
试试这个:
UIImage(命名:"checked",在:bundle,兼容: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)")
}