2014-10-28 83 views
6

我想實現一個簡單的IBDesignable UIButton子類。我希望能夠爲Interface Builder的每個控件狀態設置顏色。我知道這可能與IBInspectable關鍵字。在狀態屬性上使用KVO時,我遇到IB崩潰問題。 IBDesignable調試器在deinit時崩潰。有誰知道我可以如何與KVO和IBDesignable一起工作?IBDesignable UIButton子類

@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) 
    } 

} 

回答

6
我有類似的東西

問題是init()方法,重構我的代碼它就像一個魅力後導致崩潰。也許它會幫助你:

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

override func prepareForInterfaceBuilder() { 
    self._setup() 
} 
+1

感謝尖丹尼爾。我嘗試了上述,現在抱怨說我的IBInspectable屬性不符合鍵值編碼。所以我只是在運行時使用宏來添加/刪除觀察者。接受MACRO提示的這個答案。 – 2014-10-28 14:49:42

6

對於的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() 
    } 
} 
+0

我注意到,如果你在init(frame:)'''中刪除'''setupViews()''調用,那麼安裝程序仍然可以在IB和應用程序中使用。是否有我們需要從該init調用設置的原因? – 2016-03-28 17:38:09

+0

@PaulVanWieren有趣。我記得,它不起作用。在setupViews()中設置斷點並檢查誰在調用它:) – skywinder 2016-03-29 09:04:52

+5

@PaulVanWieren - 如果在代碼中創建視圖,則使用init(frame :)方法。在故事板和筆尖中創建的視圖使用init(編碼器:)方法。如果您不打算在代碼中創建視圖,則不需要使用init(frame :)方法,但通常爲了完整而包含它。 – 2016-04-23 02:37:49