Home > OS >  Ambiguous UILabel height in autoresizing UITableViewCell
Ambiguous UILabel height in autoresizing UITableViewCell

Time:09-17

I am having a hard time making my implementation of UITableView with automatic cell sizing. I am trying to use a UIStackView with 2 labels inside cell with automatic size.

It looks good overall but I am getting the following runtime issues:

layout issues in xcode

enter image description here

I feel like the constraints I have should be enough for the use case here but I would like to get rid of the ambiguity here.

How that can be achieved? What is the common approach to take here?

I have prepared a sample project that simplifies my use case but still demonstrates the issue. Here is my controller:

class ViewController: UIViewController {

    struct CellData {
        let title: String
        let subtitle: String
    }

    let table = UITableView()

    let data = [
        CellData(title: "Foo", subtitle: "Bar"),
        CellData(title: "Baz", subtitle: "FooBar")
    ]

    private let cellReuseID = "CellReuseID"

    override func viewDidLoad() {
        super.viewDidLoad()

        table.register(Cell.self, forCellReuseIdentifier: cellReuseID)
        table.dataSource = self
        table.rowHeight = UITableView.automaticDimension
        table.tableFooterView = UIView(frame: .zero)

        table.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(table)
        NSLayoutConstraint.activate([
            table.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            table.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            table.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            table.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),

        ])

    }
}

extension ViewController: UITableViewDataSource {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        data.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseID) as? Cell else {
            fatalError()
        }
        cell.title = data[indexPath.row].title
        cell.subtitle = data[indexPath.row].subtitle
        return cell
    }
}

And the cell it uses:

class Cell: UITableViewCell {

    var title: String? {
        didSet {
            titleLabel.text = title
        }
    }

    var subtitle: String? {
        didSet {
            subtitleLabel.text = subtitle
        }
    }

    let titleLabel = UILabel()

    let subtitleLabel = UILabel()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupView()
    }

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

    private func setupView() {
        let stackView = UIStackView()
        stackView.axis = .vertical
        stackView.alignment = .top
        stackView.distribution = .fill
        stackView.spacing = 8

        stackView.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(stackView)
        NSLayoutConstraint.activate([
            stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            stackView.topAnchor.constraint(equalTo: contentView.topAnchor)
        ])


        stackView.addArrangedSubview(titleLabel)
        stackView.addArrangedSubview(subtitleLabel)
    }
}

CodePudding user response:

The reason for the Ambiguous Height is because both labels have the same Content Hugging Priority.

Auto-layout makes its "best guess" and you get the desired output -- but you'll still see the issues in Debug View Hierarchy.

To get rid of it, you can give one label a higher Hugging Priority.

For example (in setupView()):

    titleLabel.setContentHuggingPriority(.defaultHigh   1, for: .vertical)
    subtitleLabel.setContentHuggingPriority(.defaultHigh, for: .vertical)
  • Related