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就好

 

关联文章: 文章

相关文章
相关标签/搜索