How to size a UIStackView depending on its content?
Asked Answered
H

2

22

I would like to have a similar behavior than the <Table> HTML tag, in the sense where the frame is sized according to its content.

In my very context, I use an UIStackView as the content view of a UITableViewCell. As items in the cell are various information, the resulting height of the cell should be variable.

My strategy is to programmatically build a cell as a UIStackView with a .Vertical axis, as in the code snippet as follows:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)

    let sv = UIStackView(frame: tableview.frame)
    sv.axis = .Vertical
    cell.addSubview(sv)
    for i in information {
        let l = UILabel()
        l.text = i
        sv.addSubViewAndArrange(l)
    }

    return cell
}

Unfortunately, the cell size does not adjust to the content, and as a result I have to set the cell height myself, as follows:

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return cellHeight     // a constant
}

How could I fix that?

Hibben answered 13/4, 2016 at 7:20 Comment(3)
I think you should properly constraint your stackView with the cell for this approach to work.Corporate
I have already tested this path (added sv T-T, L-L, R-R, B-B constraints to the cell), but this results in ultra wide cell (you barely see only one cell at a time). @zcui93Duce
StackView on it's own should be constrained with cell, so that cell will grow with it. Then setting up the subviews so that StackView will grow properly based on their "Intrinsic Content Size"Corporate
P
10

UIStackView is designed to grow its size according to the content. In order for that to work, you need to set up the constraints between the UIStackView and the UITableViewCell. For example, if UIStackView is first-item and UITableViewCell is it's super-view, then this is how the constraints look like in interface builder:

enter image description here enter image description here

If you like setting up constraints in code, that should work too.
For example, assuming stackView and cellView are the names, then above constraints' Swift-code would look like:

stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.topAnchor.constraint(equalTo: cellView.topAnchor, constant: 0).isActive = true
stackView.bottomAnchor.constraint(equalTo: cellView.bottomAnchor, constant: 0).isActive = true
stackView.leadingAnchor.constraint(equalTo: cellView.leadingAnchor, constant: 0).isActive = true
stackView.trailingAnchor.constraint(equalTo: cellView.trailingAnchor, constant: 0).isActive = true

To demonstrate that this will work, I have this for the cellForRowAt function. Basically, it puts a number of UILabel inside the UIStackView and the label count is depending on the row number.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "TableviewCell", for: indexPath) as! TableviewCell
    for i in 1...indexPath.row + 1 {
        let label = UILabel()
        label.text = "Row \(indexPath.row), Label \(i)"
        cell.stackView.addArrangedSubview(label)
    }
    return cell
}

Here is the final result:

https://github.com/yzhong52/AutosizeStackview

Perspiration answered 2/12, 2017 at 14:30 Comment(0)
M
1

I built this example I hope it helps, I've created a tableView which use a cell that contains a stackView and the views loaded in the stackView are gotten from a nib file

https://github.com/Joule87/stackView-within-TableViewCell

Mitchel answered 1/8, 2019 at 0:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.