2

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

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Bellots
  • 1,703
  • 3
  • 19
  • 29
  • You need to understand that a swift class can be used for both storyboards and xib files. But you need to redesign it on the storyboard every time you want to use it. Since you want to use this view as a UITableView's header so there's a way to do this using xibs only. Have a look at this thread hopefully it'll help you. http://stackoverflow.com/questions/31693901/design-uitableviews-section-header-in-interface-builder – Adeel Miraj Oct 02 '16 at 13:26
  • So what you are saying is that I can't create a xib file and use it for either storyboard or instantiate it in viewcontroller through NSBundle.mainBundle() ? – Bellots Oct 02 '16 at 14:03
  • Please see my answer below. – Adeel Miraj Oct 02 '16 at 15:11

2 Answers2

2

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 ;)

Bellots
  • 1,703
  • 3
  • 19
  • 29
0

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.

Adeel Miraj
  • 2,472
  • 3
  • 22
  • 32