首页 文章

自定义UIButton @IBDesignable

提问于
浏览
0

我创建了一个UIButton子类,看起来像一个复选标记 .

这是 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中看到它:
IBInspectable

奇怪的是:

  • 如果我将此属性设为 default ,则会在故事板中正确显示

uncheck

  • 但如果我在检查器中选择 onoff ,则屏幕未正确更新 .

empty

由于类标记为@IBDesignable,我希望根据在“检查器”选项卡中为此属性设置的值在IB中更新按钮外观 . 有线索吗?

2 回答

  • -1

    UIimage(命名:)方法使用主bundle但Interface Builder以不同方式加载资源 .

    试试这个:

    UIImage(命名:“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)")
     }
    

    just like this

  • 2

    我的建议是使用其他自定义函数从资产中获取图像:

    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类已经检查了状态,您可以在不创建自己的子类的情况下使用它:

    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
    

相关问题