Mathijs Segers
Mathijs Segers

Reputation: 6238

Setting a Custom HeaderView on UITable in swift, using AutoLayout from Nib

Hi I was wondering how i'd go for implementing a custom header for my UITableView and use it's autolayout for correct positioning.

I can display the cell right now but neither horizontal or vertical autolayout is applied.

in my tableViewController, I set a headerView variable to my custom nib as such:

@IBOutlet var view: UIView!

override init(frame: CGRect) { // for using CustomView in code
    super.init(frame: frame)
    self.setup()
}

required init(coder aDecoder: NSCoder) { // for using CustomView in IB
    super.init(coder: aDecoder)
    self.setup()
}

private func setup() {
    NSBundle.mainBundle().loadNibNamed("CustomHeader", owner: self, options: nil)
    self.addSubview(view)
}

which in the view class calls:

override init(frame: CGRect) { // for using CustomView in code
    super.init(frame: frame)
    self.setup()
}

required init(coder aDecoder: NSCoder) { // for using CustomView in IB
    super.init(coder: aDecoder)
    self.setup()
}

private func setup() {
    NSBundle.mainBundle().loadNibNamed("ChallengeHeader", owner: self, options: nil)
    self.addSubview(view)
}

It has some dummy content and I set a dynamic text to a label inside. The constraints are set up correctly I have it working fine for the table cells.

I have this for displaying the view as header

override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    if let view = headerView {
        return view
    }
    return nil
}


override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    if let head = headerView {
        head.setNeedsLayout()
        head.layoutIfNeeded()
        let height = head.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height

        let headerFrame = head.frame


        Debug.log("Header Height \(height)")
        return 100.0
    }
    return 0
}

Currently I'm returning the 100.0 since height is always 0, so what am I missing here to make the autolayout do it's work? Or do I need to set f/e the width programmatically?

Edit: Forgot to add, the xib has a width of 400 and it seems to remain 400 width aswell.

Upvotes: 1

Views: 5525

Answers (1)

Catalina T.
Catalina T.

Reputation: 3494

There are a few problems with your implementation.

First, you should not add the headerView as subview of self.view.

Second, if you have more than one sections, you would need a new CustomView for every section, you should not reuse it.

So your code should look something like:

override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    return NSBundle.mainBundle().loadNibNamed("CustomHeader", owner: nil, options: nil)[0] as? UIView
}

override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
}

You don't need any frame manipulation. Just make sure you return a correctly initialized CustomHeader in the viewForHeaderInSection and everything should work fine.

If you need more help or support, just let me know.


This is a small code snippet that I used to test - the only difference to your situation is that you load the headerView from the xib:

override func viewDidLoad (){

    headerView = UIView.new() // here you should have your xib loading

    var insideView = UIView.new();
    insideView.setTranslatesAutoresizingMaskIntoConstraints(false)
    headerView.addSubview(insideView);

    // This is simulating the constraints you have in your xib  
    headerView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|-[view(50)]-|", options: nil, metrics: nil, views: ["view": insideView]))     
    headerView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|-[view]-|", options: nil, metrics: nil, views: ["view": insideView]))
}

override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    return headerView
}

override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return headerView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
}

Upvotes: 6

Related Questions