7
votes

Some background: I'm building an app with a UITableView that shows a list of polls that users can vote on using a subclass of UITableViewCell. The UITableViewCell subclass has 5 IBOutlet UILabels: a question label and then 4 choice labels. A poll may have 2, 3 or 4 choice and so I'm potentially not showing the 3rd and/or 4th choice labels. Each label has "Lines" set to 0 so that they will wrap their text if it's too long.

I have layout constraints set up to ensure the cells have dynamic height as per this tutorial: http://www.raywenderlich.com/87975/dynamic-table-view-cell-height-ios-8-swift

The question label has Content Hugging Priority at 250, whereas all the choice labels are at 251. The question label has Content Compression Resistance Priority at 751, whereas all the choice labels are at 752.

When I first load the app, the 1st poll's question has too much vertical padding and the 1st choice get's cutoff with an ellipsis. But, when I scroll down and then scroll back up it fixes itself: the question label hugs it's contents and the 1st choice shows all of its contents.

Here's a GIF I made that shows the issue (focus on the top cell):

scrolling the tableView

Here's a screenshot of Interface Builder (in case it helps):

interface builder screenshot

Here's the code I'm using to populate the Cell's labels:

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    PollTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kPollCellReuseId];
    Poll *poll = [self.polls objectAtIndex: indexPath.row];

    cell.questionLabel.text = poll.question;
    cell.choiceLabel1.text = [(Choice *)[poll.choices objectAtIndex:0] text];
    cell.choiceLabel2.text = [(Choice *)[poll.choices objectAtIndex:1] text];

    BOOL hasChoice3 = poll.choices.count > 2;
    cell.choiceLabel3.text = hasChoice3 ? [(Choice *)[poll.choices objectAtIndex:2] text] : @"";
    cell.choiceLabel3TopConstraint.constant = hasChoice3 ? 8 : 0;

    BOOL hasChoice4 = poll.choices.count > 3;
    cell.choiceLabel4.text = hasChoice4 ? [(Choice *)[poll.choices objectAtIndex:3] text] : @"";
    cell.choiceLabel4TopConstraint.constant = hasChoice4 ? 8 : 0;

    return cell;
}

Why is it not rendering properly on the first try?

4
What would happen if you call [cell layoutIfNeeded] just before returning the cell in the code above? - yusuke024
That seemed to fix it but now It's complainging about auto layout for the second cell in the table: It doesn't like the vertical spacing between the 3rd and 4th choice label - Adam Langsner
I reduced the priority of the vertical spacing constraint between the 3rd and 4th choice labels and now everything seems good. Am I even going about this in the right way? this all seems a bit hacky for what I'm trying to accomplish. - Adam Langsner

4 Answers

9
votes

Adding delay on your table reloadData fixed issue for me.

I used,

self.tableView.rowHeight = UITableViewAutomaticDimension;

self.tableView.estimatedRowHeight = 500.0;

cell.layoutIfNeeded() before return cell

But adding the delay on reloading tableView fixed issue for me. The issue was only occurring on iPad.

DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                self.tableView.reloadData()      
          }

Another alternative solution worked for me,

 DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {

                //Reload with delay
                self.tableView.reloadData()

                //Again reload with delay
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                    self.tableView.reloadData()
                }
            }
5
votes

I was also getting the same issue and resolved using below trick:

    extension UITableView {
    func reloadDataWithAutoSizingCellWorkAround() {
        self.reloadData()
        self.setNeedsLayout()
        self.layoutIfNeeded()
        self.reloadData()
    }
}
0
votes

implement

-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath

and return any e.g. 100 and don't forget to set

self.tableView.rowHeight = UITableViewAutomaticDimension

at viewDidLoad

0
votes

as per @sikhapol's comment: doing [cell layoutIfNeeded] before returning the cell in -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

fixes the issue