Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically grow static table view cell height to fit label content height

Here a low quality mockup of my cell layout:

mockup

The initial height of the static cell (set in storyboard) is 80. Inside this cell are two views. The bottom view has a fix height of 40. The top view has layout constraints to align to top margin and to vertically align to the bottom view.

Inside the top view is a label (blue color) and a button (yellow color)

The label also has the constraints to align to the top of the view and to align to the bottom of the view. The idea behind that layout and constraints is that if I increase the height of the cell to 100 for example, the bottom view height stays 40 and the top view and label height is getting expanded to a height of 60.

My label has linebreak word wrapping and number of lines set to 0. What I now want is to automatically resize the cell so that the complete content of the label is getting shown when there are more than one lines. How exactly can I do that?

I tried:

self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 80.0;

This is not working. The cell height always stays 80 independend from the amount of lines in the UILabel.

I also tried:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension;
}

With the same result as my first approach.

The more complex way I tried was the following:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let heightLabel = self.heightForView(text: self.lblTitle.text!, font: UIFont(name: "Helvetica Neue", size: 18)!, width: self.lblTime.width);
    let heightView = (heightLabel + (80.0 / 2));

    print("title label height \(heightLabel)");
    print("title view height \(heightView)");

    if (heightView > 80.0) {
        return heightView;
    }

    return 80.0;
}

func heightForView(text: String, font: UIFont, width: CGFloat) -> CGFloat {
    let label: UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude));
    label.numberOfLines = 0;
    label.lineBreakMode = .byWordWrapping;
    label.font = font;
    label.text = text;
    label.sizeToFit();

    return label.frame.height;
}

output:

title label height 42.5
title view height 82.5

But this also does not seem to work since the other lines are not showing up, only the first line of the label.

How can I get this working?

EDIT

I guess the approach with calculating the label height will work when I know the width of the label. But how should I know it?

like image 932
Mulgard Avatar asked May 18 '17 18:05

Mulgard


1 Answers

From personal experience getting UITableCells to grow correctly is one of the most annoying things in iOS. The biggest gotcha is normally the constraints. If they are not perfect than the cell won't grow.

The key is to be able to draw a straight line from the top of the cell content view to the bottom of the content view. so from your example constants should look something like the following.

topView.top == contentView.top
label.top == topView.top
label.bottom == topView.bottom
topView.bottom == bottomView.top
bottomView.height == 40
bottomView.bottom == contentView.bottom

Without having that straight line the layout can't determine the correct height for the label to display all of the content.

So a rather simple version of what you are looking for in a new sample project:

class ViewController: UITableViewController {
    @IBOutlet weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        self.tableView.rowHeight = UITableViewAutomaticDimension
        self.tableView.estimatedRowHeight = 80.0

        label.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
    }

    override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableViewAutomaticDimension
    }
}

With the same layout: Layout of Table Cell

Results in the following display in the simulator. Result Image

like image 193
Binary Platypus Avatar answered Oct 04 '22 04:10

Binary Platypus