【问题标题】:IBDesignable UIButton SubclassIBDesignable UIButton 子类
【发布时间】:2014-10-28 12:23:44
【问题描述】:

我正在尝试实现一个简单的 IBDesignable UIButton 子类。我希望能够从 Interface Builder 为控件的每个状态设置颜色。我知道这可以通过 IBInspectable 关键字来实现。在 state 属性上使用 KVO 时,我遇到了 IB 崩溃的问题。 IBDesignable 调试器在 deinit 上崩溃。有谁知道我如何将 KVO 和 IBDesignable 一起使用?

@IBDesignable
class UIButtonActionButton: UIButton {

    @IBInspectable var defaultColour: UIColor = UIColor.blueColor() {
        didSet {
            self.setNeedsDisplay()
        } 
    }

    @IBInspectable var selectedColour: UIColor = UIColor.blueColor()

    @IBInspectable var disabledColour: UIColor = UIColor.grayColor()

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self._setup()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self._setup()
    }


    private func _setup(){
        self.addObserver(self, forKeyPath: "state", options: NSKeyValueObservingOptions.New, context: nil)
        self.layer.cornerRadius = 5.0
        self.layer.masksToBounds = true
    }

    override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
        self.setNeedsDisplay()
    }

    override func drawRect(rect: CGRect) {
        super.drawRect(rect)
        let context = UIGraphicsGetCurrentContext()

        if self.highlighted {
            CGContextSetFillColorWithColor(context, selectedColour.CGColor)
            CGContextFillRect(context, self.bounds)
        } else if self.state == UIControlState.Disabled {
            CGContextSetFillColorWithColor(context, disabledColour.CGColor)
            CGContextFillRect(context, self.bounds)
        } else {
            CGContextSetFillColorWithColor(context, defaultColour.CGColor)
            CGContextFillRect(context, self.bounds)
        }
    }

    deinit {
        self.removeObserver(self, forKeyPath: "state", context: nil)
    }

}

【问题讨论】:

    标签: xcode xcode6 ibdesignable


    【解决方案1】:

    对于 Xcode 7.2@IBDesignable UIButton Subclass 的通用代码如下所示:

    import UIKit
    
    @IBDesignable class MyButton: UIButton {
    
        //this init fires usually called, when storyboards UI objects created:
        required init?(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)
            self.setupViews()
        }
    
        //This method is called during programmatic initialisation
        override init(frame: CGRect) {
            super.init(frame: frame)
            setupViews()
        }
    
    
        func setupViews() {
            //your common setup goes here
        }
    
        //required method to present changes in IB
        override func prepareForInterfaceBuilder() {
            super.prepareForInterfaceBuilder()
            self.setupViews()
        }
    }
    

    【讨论】:

    • 我注意到,如果您删除init(frame:) 中的setupViews() 调用,设置在IB 和应用程序中仍然有效。我们是否有理由需要从该初始化中调用设置?
    • @PaulVanWieren 很有趣。我记得,它不起作用。在setupViews() 中设置断点并检查,是谁在调用它:)
    • @PaulVanWieren - 如果在代码中创建视图,则使用 init(frame:) 方法。在故事板和 nib 中创建的视图使用 init(coder:) 方法。如果您不打算在代码中创建视图,则不严格要求具有 init(frame:) 方法,但通常包含它是为了完整性。
    • 为我节省了很多时间和精力
    • 请注意,如果您使用任何@IBInspectable,您只会在“awakeFromNib”中将它们设置在运行时,因此您也需要添加它: override func awakeFromNib() { super.awakeFromNib() setupViews( ) }。也许你需要从 init(withDecoder) 中删除 setupViews()???
    【解决方案2】:

    我遇到了类似的问题,问题是 init() 方法在重构我的代码后导致崩溃,它就像一个魅力。也许它会帮助你:

    #if !TARGET_INTERFACE_BUILDER
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self._setup()
    }
    #endif
    
    override func prepareForInterfaceBuilder() {
        self._setup()
    }
    

    【讨论】:

    • 感谢丹尼尔的提示。我尝试了上述方法,现在它抱怨我的 IBInspectable 属性不符合键值编码。所以我只在运行时使用宏来添加/删除观察者。接受 MACRO 提示的这个答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-22
    • 1970-01-01
    • 1970-01-01
    • 2019-04-03
    • 2020-12-03
    • 1970-01-01
    • 2013-01-09
    相关资源
    最近更新 更多