Search code examples
iosswiftuitableviewautolayoutsnapkit

How to create programatically UITableViewCell using SnapKit that autoresized its height?


Something seemingly simple turned out to be really hard. I have browsed already multiple topics here and on SnapKit GitHub but failed to solve my issue.

I want to have UITableViewCell with a label that is positioned in the middle let's say both 50 from top and bottom the cell.

It's worth to mention that the cell is created programatically

override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    self.addSubview(titleLabel)
    titleLabel.snp.makeConstraints { (make) -> Void in
        make.topMargin.equalToSuperview().offset(50.0)
        make.left.equalToSuperview().inset(UIView.getValueScaledByScreenWidthFor(baseValue:10.0))
        make.bottomMargin.equalToSuperview().offset(50.0)

    }
}

In the ViewController I tried both approaches for automatic cell height:

 extension EpisodeViewController: UITableViewDelegate {
  func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
  }
}

And

tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableViewAutomaticDimension

in viewDidLoad() method

What I get is:

enter image description here

Each of these three cells should be populated with "Test" - instead it has pushed down the label below the respective cell without resizing the cell.

Tried many various combinations such as:

1) Setting contraint priority to 999 - no change

2) Adding to contentView instead of self - does not show at all

3) Using top instead of topMargin etc - makes no difference

Could you advice me what's wrong with this code, and what is the general rule of thumb while using SnapKit in programatically created cells that should autoresize its height based on constraint?

Thanks in advance

EDIT

UITableView DataSource methods

extension EpisodeViewController: UITableViewDataSource {

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: EpisodeHeaderCell = tableView.dequeueReusableCell(for: indexPath)
    cell.viewModel = viewModel
    return cell
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 3
}
func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

}

Solution

  •     label.snp.makeConstraints {
            $0.left.equalToSuperview().offset(10)
            $0.right.equalToSuperview().offset(-10)
            $0.top.equalToSuperview().offset(50)
            $0.bottom.equalToSuperview().offset(-50)
        }
    

    Here is the whole code of viewController.swift file.

    class TestCell: UITableViewCell {
        static let identifier: String = "test_cell_identifier"
    
        var label: UILabel!
    
        override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            self.configure()
        }
    
        func configure() {
            label = UILabel(frame: .zero)
            self.contentView.addSubview(label)
            label.snp.makeConstraints {
                $0.left.equalToSuperview().offset(10)
                $0.right.equalToSuperview().offset(-10)
                $0.top.equalToSuperview().offset(50)
                $0.bottom.equalToSuperview().offset(-50)
            }
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    }
    
    class ViewController: UIViewController {
        var data: [String] = [
            "Test1",
            "Test2",
            "Test3"
        ]
    
        var tableView: UITableView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            tableView = UITableView(frame: .zero)
            self.view.addSubview(tableView)
            tableView.snp.makeConstraints {
                $0.edges.equalToSuperview()
            }
            tableView.register(TestCell.self, forCellReuseIdentifier: TestCell.identifier)
            tableView.dataSource = self
            tableView.delegate = self
    
            tableView.estimatedRowHeight = 100
        }
    }
    
    extension ViewController: UITableViewDelegate, UITableViewDataSource {
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return data.count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: TestCell.identifier, for: indexPath) as! TestCell
            cell.label.text = data[indexPath.item]
            return cell
        }
    }