Note that there are some explanatory texts on larger screens.

plurals
  1. PODynamic UILabel Heights/Widths in UITableViewCell in all Orientations
    primarykey
    data
    text
    <p>My question essentially boils down to the <strong>best way to support dynamic heights of UILabel's (and I suppose other elements) in a UITableCell</strong>, and also <strong>correctly resize the label width/height and cell heights when rotating</strong>.</p> <p>I'm aware of how to get the expected height of UILabels, and size the heights accordingly, but things seem to get pretty tricky when you support landscape orientation as well.</p> <p>I'm thinking this might go the route of <a href="https://stackoverflow.com/questions/1303695/adjusting-the-positions-of-the-labels-in-a-uitableviewcell">layoutSubviews</a>, but I'm not sure how you would combine that with the table needing to calculate the height of cells. <a href="https://stackoverflow.com/questions/6105489/autoresizing-uitablecells-contents-in-landscape">Another interesting post</a> sets the frame manually on init to make sure they are doing calculations off a known quantity, but that only addresses part of the issue.</p> <p>So here's an image of what I'm dealing with, with red arrows pointing to the dynamic height labels, and blue arrows pointing towards the cells that will change height.</p> <p><img src="https://i.stack.imgur.com/nRfo2.png" alt="Dynamic UILabel/Cell Height/Width"></p> <p>I've managed to get it working correctly, but not sure if its the correct method. </p> <h2>Here's a few of the things I learned:</h2> <ul> <li>The cell.frame in <code>cellForRowAtIndexPath</code> always gives its size in portrait mode. (ie. for the iphone app, it always reports 320).</li> <li>Storing a prototype cell for reference in a property has the same issue, always in portrait mode</li> <li>autoresizing masks for the width of labels seem to be useless in this use case, and in fact cause issues with the calculated height on rotation</li> <li>The tableView.frame in <code>cellForRowAtIndexPath</code> gives its size in the correct orientation</li> <li>You need to call <code>[tableView reloadData]</code> on rotation. I couldn't find any other way to update the cell and label heights</li> </ul> <h2>Here are the steps I took to get this working for me:</h2> <ol> <li>Disable any autoresize masks on UILabels, as they interfere with getting the right label height for some reason</li> <li><p>On <code>viewDidLoad</code> I grab a reference to each label font, and a float for the label width percentage compared to the tableView in portrait</p> <pre><code>CWProductDetailDescriptionCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"DescriptionCell"]; self.descriptionLabelWidthPercentage = cell.descriptionLabel.frame.size.width / 320; self.descriptionLabelFont = cell.descriptionLabel.font; </code></pre></li> <li><p>In <code>heightForRowAtIndexPath</code> I calculate the cell height using the tableView width and the percentage I already grabbed:</p> <pre><code>case TableSectionDescription: CGFloat labelWidth = self.tableView.frame.size.width * self.descriptionLabelWidthPercentage; CGSize newLabelFrameSize = [self sizeForString:self.product.descriptionText WithConstraint:CGSizeMake(labelWidth, MAXFLOAT) AndFont:self.descriptionLabelFont]; return newLabelFrameSize.height + kTextCellPadding; </code></pre></li> <li><p>In <code>cellForRowAtIndexPath</code> I calculate the frame for the label frame and update it</p> <pre><code>cell = [tableView dequeueReusableCellWithIdentifier:@"DescriptionCell"]; ((CWProductDetailDescriptionCell *)cell).descriptionLabel.text = self.product.descriptionText; CGRect oldFrame = ((CWProductDetailDescriptionCell *)cell).descriptionLabel.frame; CGFloat labelWidth = self.tableView.frame.size.width * self.descriptionLabelWidthPercentage; CGSize newLabelFrameSize = [self sizeForString:self.product.descriptionText WithConstraint:CGSizeMake(labelWidth, MAXFLOAT) AndFont:((CWProductDetailDescriptionCell *)cell).descriptionLabel.font]; ((CWProductDetailDescriptionCell *)cell).descriptionLabel.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, labelWidth, newLabelFrameSize.height); </code></pre></li> <li><p>In <code>didRotateFromInterfaceOrientation</code> you need to <code>[self.tableView reloadData]</code></p></li> </ol> <h2>Problems with this method:</h2> <ol> <li>You can't leverage the autoresizing masks and margins you <a href="http://screencast.com/t/Zpxf2HAcI" rel="nofollow noreferrer">might set in IB</a> <ul> <li>those don't seem to fire until after you've returned the cell in <code>cellForRowAtIndexPath</code> <strong>(not sure if this is exactly true)</strong></li> <li>they mess up the height calculation somehow, and your labels end up <a href="http://screencast.com/t/j6DJpVYv" rel="nofollow noreferrer">taller</a> than <a href="http://screencast.com/t/aD3AxDAU" rel="nofollow noreferrer">desired</a> in landscape.</li> </ul></li> <li>If your label's width isn't an equal percentage in <a href="http://screencast.com/t/GJglYeeKuD4" rel="nofollow noreferrer">portrait</a> and <a href="http://screencast.com/t/8i72MeRNDKSM" rel="nofollow noreferrer">landscape</a>, you'll need to know both percentages</li> <li>You need to know/calculate your labels width percentages. Ideally you would be able to calculate these on the fly after an auto-resizing mask has done its thing. </li> <li>It just feels clumsy. I have a feeling I'm going to run into more headaches in editing mode with indenting.</li> </ol> <p><strong>So. What is the right way to do this? I've seen lots of SO questions, but none quite address this exactly.</strong></p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload