swift 之xib自定義view可視化到storyboard

首先直入正題:@IBInspectable & @IBDesignablehtml

對於 @IBInspectable 和 @IBDesignable 可詳見官方文檔 : Creating a Custom View That Renders in Interface Builderios

 

固然也能夠閱讀下中文版的: http://nshipster.cn/ibinspectable-ibdesignable/swift

若是自定view是本身用純代碼寫的,對於上面兩種處理都比較簡單,只須要指定類名便可。xcode

 

可是若是這個自定義view是用寫的,那麼若是讓xib的界面直接render到storyboard呢?app

1. 建立一個IDView,添加一個IDView.Xibiview

 

2. 對IDCard.xib添加約束ide

 

3. 在IDCard.xib的 File's Owner class 設置爲IDCard:ui

 

4. 在IDCard.swift中添加以下代碼,把xib的view連線到代碼上的contentView:spa

5. 綁定xib,實現 @IBInspectable, @IBDesignable這幾部分代碼3d

 

@IBDesignable
class IDCard: UIView {
    
    @IBOutlet var contentView: UIView!
    

    @IBInspectable
    var cornerRadius: CGFloat = 0 {
        didSet {
            layer.cornerRadius = cornerRadius
            layer.masksToBounds = cornerRadius > 0
        }
    }
    @IBInspectable
    var borderWidth: CGFloat = 0 {
        didSet {
            layer.borderWidth = borderWidth
        }
    }
    @IBInspectable
    var borderColor: UIColor? {
        didSet {
            layer.borderColor = borderColor?.CGColor
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        initialFromXib()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initialFromXib()
    }
    
    func initialFromXib() {
        let bundle = NSBundle(forClass: self.dynamicType)
        let nib = UINib(nibName: "IDCard", bundle: bundle)
        contentView = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
        contentView.frame = bounds
        addSubview(contentView)
        
    }
    
}

 

6. 在Main.storyboard實現拖入view,並指定其class爲IDCard,並對其進行約束

 

 

 

 

 

 

7. 運行代碼,結果以下

 

 

總結遇到的一些坑:

 1. 如何讓 sb上的約束生效

 2. 如何讓xib渲染到sb上

 上面的兩個問題都在initialFromXib上解決

 

func initialFromXib() {
        let bundle = NSBundle(forClass: self.dynamicType) let nib = UINib(nibName: "IDCard", bundle: bundle) contentView = nib.instantiateWithOwner(self, options: nil)[0] as! UIView  contentView.frame = bounds // 問題1的解決方案 addSubview(contentView) }

 

   那麼爲何要設置contentView.frame = bounds?

   首先咱們都知道程序首先會加載vc對應的sb,那麼sb上相關的約束等會對其上的view進行渲染,那麼這個時候 IDCard.xib也會獲得渲染,若是咱們這個時候不設置contentView的frame的話,

   那麼這個時候contentView的frame將會被xib上的覆蓋掉,那麼這個時候contentView的大小隻能是你在xib上的大小。這個時候也是凸顯爲何要有contentView這個屬性了。由於

    self = nib.instantiateWithOwner(self, options: nil)[0] as! UIView

   這是不被編譯經過的。

  問題2, 在寫這個例子的時候,我加載這個

  contentView = NSBundle.mainBundle().loadNibNamed("Xib", owner: self, options: nil)[0] as! UIView  

   替代

 let bundle = NSBundle(forClass: self.dynamicType)

   let nib = UINib(nibName: "IDCard", bundle: bundle)

  contentView = nib.instantiateWithOwner(self, options: nil)[0] as! UIView 

  這個時候咱們看在sb上看不到IDCard這個view,或者報錯"Failed to update auto layout status"。緣由待查,可參考  

  還有一個可能的緣由: 

  NIb加載會把xib文件加載到內存中,讀取快,常常使用的xib文件可使用nib加載,

    Bundle加載,每次會從磁盤上加載,效率會慢一點

 

 

   3. 還有在其餘須要注意的點

   在用@IBDesignable時候, 你最好重寫init(frame:) 和 init(coder:)這兩個初始化方法

   在xib中,你不須要給這個view的class設置爲IDCard,默認的UIView就好

 

關聯文章: 文章

相關文章
相關標籤/搜索