Bellots
Bellots

Reputation: 1773

Be able to load xib from both Storyboard and ViewController

I'm trying to create the perfect solution to make a custom UIView subclass directly from code and in Storyboard. However, I didn't found any solution.

For an IBDesignable solution through storyboard, I followed this example http://supereasyapps.com/blog/2014/12/15/create-an-ibdesignable-uiview-subclass-with-code-from-an-xib-file-in-xcode-6 and works perfectly.

But if I try to call this subclass through UIViewController by calling this Extension method:

extension UIView {
    class func loadFromNibNamed(nibNamed: String, bundle : NSBundle? = nil) -> UIView? {
        return UINib(
            nibName: nibNamed,
            bundle: bundle
        ).instantiateWithOwner(nil, options: nil)[0] as? UIView
    }
}

It crashes and says that misses this class is not key value coding-compliant for the key.

Has anybody found a solution to share with me for have both possibilities?

I need it because I should use this UIView in storyboard and also as UITableview SectionHeader

Upvotes: 2

Views: 2114

Answers (2)

Bellots
Bellots

Reputation: 1773

To preserve both cases, I preferred to write this inside my subclass declaration:

@IBDesignable class CustomView: UIView {

    var view: UIView!

    @IBOutlet weak var button: UIButton!
    @IBOutlet weak var label: UILabel!


    func xibSetup() {
        view = loadViewFromNib()
        view.frame = bounds
        view.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
        addSubview(view)
    }

    func loadViewFromNib() -> UIView {

        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: "CustomView", bundle: bundle)
        let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView

        return view
    }


    override init(frame: CGRect) {
        super.init(frame: frame)
        xibSetup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        xibSetup()
    } 
}

In this way I can see and add it inside my storyboard. In ViewForHeaderInSection method, I wrote this:

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

let header = UIView()

let view:CustomView = CustomView(frame: CGRect(x: 0, y: 0, width:  self.view.frame.width, height: 30))

view.label.text = "header title: \(section)"

header.addSubview(view)


return header

}

And so it works ;)

Upvotes: 2

Adeel Miraj
Adeel Miraj

Reputation: 2496

Here's how you can use an xib in a view controller that is instantiated from storyboard (in your case as a section header of a UITableView).

  1. Create an xib file, design your interface, and the necessary connections to of the UI elements with the IBOutlets in your swift file
  2. In viewDidLoad method of your view controller class (one that is instantiated from the storyboard)

    // Name your xib and swift class as Header
    
    let headerNib = UINib(nibName: "Header", bundle: nil)
    self.tableView.registerNib(headerNib, forHeaderFooterViewReuseIdentifier: "header")
    
  3. Implement the UITableViewDelegate method viewForHeaderInSection

    func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    
    let header = tableView.dequeueReusableHeaderFooterViewWithIdentifier("header") as! Header
    // Customise your header view here
    
    return header;
    }
    

That's all you need to do.

Upvotes: 0

Related Questions