Search code examples
iosswiftuitableviewnslayoutconstraint

Rows in table view do not expand the width of it and are stacked Swift


I have spent an hour trying to figure out what I'm doing wrong but no success. below is the code and an image of the result. All the rows appear one on top of the other in the first row of the table. and the row does not expand the width of the table as I have set it in the constraints. What am I doing wrong? Thank you. The table view class:

class TableViewListType: UITableView { 
    override init(frame: CGRect, style: UITableView.Style) {
        super.init(frame: frame, style: style)
        translatesAutoresizingMaskIntoConstraints = false
        allowsSelection = true
        allowsMultipleSelection = false
        allowsSelectionDuringEditing = true
        allowsMultipleSelectionDuringEditing = true
        dragInteractionEnabled = false
        backgroundColor = .clear
        separatorColor = .white
        separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        indicatorStyle = .white
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

The row classes for the table view:

class SuperRowForProfileAttributesTable: UITableViewCell {
    //MARK: - Properties.
    internal let firstLabel: LabelForRowInList = {
        let label = LabelForRowInList(frame: .zero)
        return label
    }()
    internal let secondLabel: LabelForRowInList = {
        let label = LabelForRowInList(frame: .zero)
        return label
    }()
    internal let thirdLabel: LabelForRowInList = {
        let label = LabelForRowInList(frame: .zero)
        return label
    }()
    internal let fourthLabel: LabelForRowInList = {
        let label = LabelForRowInList(frame: .zero)
        return label
    }()
    //MARK: - Init.
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        translatesAutoresizingMaskIntoConstraints = false
        clipsToBounds = true
        backgroundColor = .clear
        setupViews()
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    //MARK: - Functions.
    internal func setupViews() {
        addSubview(firstLabel)
        addSubview(secondLabel)
        addSubview(thirdLabel)
        addSubview(fourthLabel)
        let firstConstraints = [
            firstLabel.topAnchor.constraint(equalTo: topAnchor),
            firstLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
            firstLabel.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 1/3),
            firstLabel.widthAnchor.constraint(equalTo: widthAnchor)
        ]
        NSLayoutConstraint.activate(firstConstraints)
        let secondConstraints = [
            secondLabel.topAnchor.constraint(equalTo: firstLabel.bottomAnchor),
            secondLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
            secondLabel.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 1/3),
            secondLabel.widthAnchor.constraint(equalTo: widthAnchor)
        ]
        NSLayoutConstraint.activate(secondConstraints)
        let thirdConstraints = [
            thirdLabel.topAnchor.constraint(equalTo: secondLabel.bottomAnchor),
            thirdLabel.leadingAnchor.constraint(equalTo: leadingAnchor),
            thirdLabel.trailingAnchor.constraint(equalTo: centerXAnchor),
            thirdLabel.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 1/3),
        ]
        NSLayoutConstraint.activate(thirdConstraints)
        let fourthConstraints = [
            fourthLabel.topAnchor.constraint(equalTo: secondLabel.bottomAnchor),
            fourthLabel.leadingAnchor.constraint(equalTo: centerXAnchor),
            fourthLabel.trailingAnchor.constraint(equalTo: trailingAnchor),
            fourthLabel.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 1/3)
        ]
        NSLayoutConstraint.activate(fourthConstraints)
    }
}
class RowForExperienceInProfileTable: SuperRowForProfileAttributesTable {
    //MARK: - Properties.
    internal var valueForExperienceRow: ExperienceModelForProfileAttributes! {
        didSet {
            firstLabel.text = valueForExperienceRow.jobTitle
            secondLabel.text = valueForExperienceRow.companyName
            thirdLabel.text = valueForExperienceRow.startedWork
            fourthLabel.text = valueForExperienceRow.finishedWork
        }
    }
}
class RowForSkillInProfileTable: SuperRowForProfileAttributesTable {
    //MARK: - Properties.
    internal var valueForSkillRow: SkillsModelForProfileAttributes! {
        didSet {
            firstLabel.text = valueForSkillRow.skill
        }
    }
    //MARK: - Init.
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupViews()
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func setupViews() {
        addSubview(firstLabel)
        let firstConstraints = [
            firstLabel.centerXAnchor.constraint(equalTo: centerXAnchor),
            firstLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
            firstLabel.widthAnchor.constraint(equalTo: widthAnchor, constant: 0),
            firstLabel.heightAnchor.constraint(equalTo: heightAnchor, constant: 0)
        ]
        NSLayoutConstraint.activate(firstConstraints)
    }
}
class RowForEducationInProfileTable: SuperRowForProfileAttributesTable {
    //MARK: - Properties.
    internal var valueForEducationRow: EducationModelForProfileAttributes! {
        didSet {
            firstLabel.text = valueForEducationRow.institutionName
            secondLabel.text = valueForEducationRow.degreeName
            thirdLabel.text = valueForEducationRow.startedStudy
            fourthLabel.text = valueForEducationRow.finishedStudy
        }
    }
}

The VC:

 fileprivate var experienceForProfile = [ExperienceModelForProfileAttributes(jobTitle: "Tester", companyName: "Testing Company", startedWork: "May 2019", finishedWork: "October 2019"), ExperienceModelForProfileAttributes(jobTitle: "Welder", companyName: "Welding Company", startedWork: "January 2018", finishedWork: "May 2020")]
    fileprivate var skillsForProfile = [SkillsModelForProfileAttributes]()
    fileprivate var educationForProfile = [EducationModelForProfileAttributes]()
fileprivate lazy var tableForAttributes: TableViewListType = {
        let table  = TableViewListType(frame: .zero, style: .plain)
        table.delegate = self
        table.dataSource = self
        return table
    }()
 override func viewDidLoad() {
        super.viewDidLoad()
        navigationController?.navigationBar.isHidden = true
        tableForAttributes.register(RowForExperienceInProfileTable.self, forCellReuseIdentifier: firstIDForTable)
        tableForAttributes.register(RowForSkillInProfileTable.self, forCellReuseIdentifier: secondIDForTable)
        tableForAttributes.register(RowForEducationInProfileTable.self, forCellReuseIdentifier: thirdIDForTable)
    }
func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        var numberOfRows = 0
        switch selectedMimicIndex {
        case 0: numberOfRows = experienceForProfile.count
        case 1: numberOfRows = skillsForProfile.count
        case 2: numberOfRows = educationForProfile.count
        default: print("nu such rows for attributes table in own profile")
        }
        return numberOfRows
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        switch selectedMimicIndex {
        case 0: let cell = tableView.dequeueReusableCell(withIdentifier: firstIDForTable, for: indexPath) as! RowForExperienceInProfileTable
        cell.valueForExperienceRow = experienceForProfile[indexPath.row]
        return cell
        case 1: let cell = tableView.dequeueReusableCell(withIdentifier: secondIDForTable, for: indexPath) as! RowForSkillInProfileTable
        cell.valueForSkillRow = skillsForProfile[indexPath.row]
        return cell
        case 2: let cell = tableView.dequeueReusableCell(withIdentifier: thirdIDForTable, for: indexPath) as! RowForEducationInProfileTable
        cell.valueForEducationRow = educationForProfile[indexPath.row]
        return cell
        default: return UITableViewCell()
        }
    }

The selectedMimicIndex value is changed the didSelectItem() function of the collection view that I have; a cv that controls what cells the table displays. reloadData() is called here after the Int value is changed when the user changes the selected cv cell. the result is this: Also notice that the second row is much taller that it should be; ignores the height that I have specified.


Solution

  • For every label you need to set and add it to contentView

    firstLabel.translatesAutoresizingMaskIntoConstraints = false
    contentView.addSubview(firstLabel)
    

    also the most bottom label to bottom of cell

    fourthLabel.bottomAnchor.constraint(equalTo:self.contentView.bottomAnchor, constant:-20)