Gamal Elsayed
Gamal Elsayed

Reputation: 63

Section Header Not Showing in Programmatic UITableView

I'm trying to learn how to create different UI elements programmatically. I'm facing the following problem with my UITableView..

I have 2 .swift files, on one hand, we have..

        struct SettingsView {

        let settingsCustomTable: UITableView = {

            let aTable = UITableView()
                aTable.sectionHeaderHeight = 42
                aTable.tableFooterView = UITableViewHeaderFooterView(frame:CGRect(x:0,
                                                                                  y:0,
                                                                                  width:aTable.frame.width,
                                                                                  height:0))

                aTable.register(SettingsCustomHeader.self, forHeaderFooterViewReuseIdentifier:"customHeader")
                aTable.register(SettingsCustomCell.self, forCellReuseIdentifier:"customCell")

            return aTable
        }()

    }


    ////////////////////////////////
    //  custom cell class below   //
    ////////////////////////////////

    private class SettingsCustomCell: UITableViewCell {

        override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)

            contentView.addSubview(customCellLabel)
            customCellLabel.frame = CGRect(x:16,
                                           y:0,
                                           width: self.frame.width,
                                           height:self.frame.height)
        }

        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }

        private let customCellLabel: UILabel = {

            let aLabel = UILabel()
                aLabel.text = "custom label"
                aLabel.textColor = appGreenColor(alphaIs: 1)

            return aLabel
        }()
    }


    //////////////////////////////////
    //  custom header class below   //
    //////////////////////////////////

    private class SettingsCustomHeader: UITableViewHeaderFooterView {

        override init(reuseIdentifier: String?) {
            super.init(reuseIdentifier: reuseIdentifier)

            contentView.addSubview(customHeaderLabel)
            customHeaderLabel.frame = CGRect(x:0,
                                           y:0,
                                           width: self.frame.width,
                                           height:self.frame.height)
        }

        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }

        private let customHeaderLabel: UILabel = {

            let aLabel = UILabel()
            aLabel.text = "custom header"
            aLabel.textColor = UIColor.white
            aLabel.backgroundColor = UIColor.red

            return aLabel
        }()

    }

and on the other .swift file, I have the controller as follows..

class SettingsVC: UIViewController, UITableViewDelegate, UITableViewDataSource {

    private let instanceOfSettingsView = SettingsView()

    override func loadView() {
        super.loadView()

        instanceOfSettingsView.settingsCustomTable.delegate = self
        instanceOfSettingsView.settingsCustomTable.dataSource = self

        view.addSubview(instanceOfSettingsView.settingsCustomTable)
        instanceOfSettingsView.settingsCustomTable.frame = CGRect(x: 0,
                                                                  y: 0,
                                                                  width: self.view.frame.width,
                                                                  height: self.view.frame.height)

    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 2
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath)
    }

    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        return tableView.dequeueReusableHeaderFooterView(withIdentifier: "customHeader")
    }

As you can see, i'm using the exact same approach for both the cells and the header section. But for some odd reason, I get the below output (Please check the screenshot at the end of this post)..

Could you advise what am I missing..? I'm trying to have my view laid separate from my controller, which is successful except for that small part.

appreciate your help.

enter image description here

Upvotes: 0

Views: 867

Answers (1)

DonMag
DonMag

Reputation: 77423

Add a line to your custom header's init func:

   override init(reuseIdentifier: String?) {
        super.init(reuseIdentifier: reuseIdentifier)

        contentView.addSubview(customHeaderLabel)
        customHeaderLabel.frame = CGRect(x:0,
                                       y:0,
                                       width: self.frame.width,
                                       height:self.frame.height)

        // add this line
        print("w:", self.frame.width, "h:", self.frame.height)
    }

You will see that, at this point, the frame is not set. Your debug console output should be:

w: 0.0 h: 0.0
w: 0.0 h: 0.0

If you set constraints on customHeaderLabel instead of setting its frame, you should see the label. (It can also help to set a background color, just so you can see what's what).

So, to "fill out" this answer...

Using Visual Format Language:

override init(reuseIdentifier: String?) {
    super.init(reuseIdentifier: reuseIdentifier)

    contentView.addSubview(customHeaderLabel)

    customHeaderLabel.translatesAutoresizingMaskIntoConstraints = false

    NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-8-[chl]|", options: [], metrics:[:], views:["chl":customHeaderLabel]))
    NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|[chl]|", options: [], metrics:[:], views:["chl":customHeaderLabel]))

}

Or using anchors and .constraint format:

override init(reuseIdentifier: String?) {
    super.init(reuseIdentifier: reuseIdentifier)

    contentView.addSubview(customHeaderLabel)

    customHeaderLabel.translatesAutoresizingMaskIntoConstraints = false

    customHeaderLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8.0).isActive = true
    customHeaderLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 0.0).isActive = true
    customHeaderLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: 0.0).isActive = true
    customHeaderLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: 0.0).isActive = true

}

Upvotes: 1

Related Questions