8

My text is two lines long in portrait mode. When I switch to landscape mode, it fits into a single line. I'm using static tableview cells via a storyboard; how can I resize the row to fit snugly?

The screen is a signin screen.

  • The first cell contains some explanation text
  • The second is a text field for entering the account name
  • The third is a secure text field for entering the password
  • The fourth (and last) cell contains the signin button. The return key on the keyboard submits the form or switches the focus as appropriate
Steven Fisher
  • 44,462
  • 20
  • 138
  • 192

3 Answers3

9

Use UITableView's heightForRowAtIndexPath :

 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 {
   int topPadding = 10;
   int bottomPadding = 10;
   float landscapeWidth = 400;
   float portraitWidth = 300;

   UIFont *font = [UIFont fontWithName:@"Arial" size:22];

   //This is for first cell only if you want for all then remove below condition
   if (indexPath.row == 0) // for cell with dynamic height
   {
      NSString *strText = [[arrTexts objectAtIndex:indexPath.row]; // filling text in label  
     if(landscape)//depends on orientation
     {
       CGSize maximumSize = CGSizeMake(landscapeWidth, MAXFLOAT); // change width and height to your requirement
     }
     else //protrait
     {
       CGSize maximumSize = CGSizeMake(portraitWidth, MAXFLOAT); // change width and height to your requirement
     }

     //dynamic height of string depending on given width to fit
     CGSize textSize = CGSizeZero;
     if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")
     {
        NSMutableParagraphStyle *pstyle = [NSMutableParagraphStyle new];
        pstyle.lineBreakMode = NSLineBreakByWordWrapping;

        textSize = [[strText boundingRectWithSize:CGSizeMake(width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName :font,NSParagraphStyleAttributeName:[pstyle copy]} context:nil] size];
     }
     else // < (iOS 7.0)
     {
        textSize = [strText sizeWithFont:font constrainedToSize:maximumSize lineBreakMode:NSLineBreakByWordWrapping] 
     }

     return (topPadding+textSize.height+bottomPadding) // caculate on your bases as u have string height
   }
   else
   {
       // return height from the storyboard
       return [super tableView:tableView heightForRowAtIndexPath:indexPath];
   }
 }

EDIT : Added for support for > and < ios7 and as sizeWithFont method is deprecated in iOS 7.0

Paresh Navadiya
  • 38,095
  • 11
  • 81
  • 132
  • If I do this, I need to manually control the height of each cell rather than just my first, correct? (That's not awful, I just want to be clear.) – Steven Fisher Aug 16 '12 at 05:28
  • Thanks. I assumed this call wouldn't function with storyboards + static cells, but I've checked and you're absolutely right. – Steven Fisher Aug 16 '12 at 05:39
  • I hope you don't mind, but I found a way to get the height for other rows from the storyboard and edited it into your answer. – Steven Fisher Aug 16 '12 at 05:42
  • 1
    This works, by the way, because although the UITableViewController "should not implement the data source protocol" to provide content for static table views, the method above is part of the _delegate_ protocol, which it seems can still be used to tweak the style and layout defined by the storyboard. (Quote is from Apple's TableView Programming Guide at https://developer.apple.com/library/ios/documentation/userexperience/conceptual/tableview_iphone/CreateConfigureTableView/CreateConfigureTableView.html#//apple_ref/doc/uid/TP40007451-CH6-SW27 . – algal Nov 28 '13 at 18:55
  • Just used the answer and it works, except for one little thing. `size` is not a method on `CGRect`, you need to use the property. So it would be: `strSize = [[strText boundingRectWithSize:CGSizeMake(width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName :font,NSParagraphStyleAttributeName:[pstyle copy]} context:nil].size];` – Belle Nov 17 '15 at 15:55
8

I've had success with a little simpler implementation. As long as your static table view has proper constraints on the cells, you can ask the system to size it for you:

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
    let cell = self.tableView(self.tableView, cellForRowAtIndexPath: indexPath)
    let height = ceil(cell.systemLayoutSizeFittingSize(CGSizeMake(self.tableView.bounds.size.width, 1), withHorizontalFittingPriority: 1000, verticalFittingPriority: 1).height)
    return height
}
Aaron Scherbing
  • 507
  • 6
  • 6
  • 1
    This was a very old question. In the modern iOS if your constraints are proper and you add an estimation function that returns `UITableViewAutomaticDimension` you don't even need to write the height method. :) – Steven Fisher Nov 19 '15 at 19:58
  • 2
    This answer may still be relevant. I've run into instances in iOS 9 where a static table view with proper constraints will not dynamically resize correctly after changing a label's text. The above work-around solves the problem, while UITableViewAutomaticDimension does not. – Aaron Scherbing Nov 29 '15 at 21:46
  • Calling `tableView.cellForRowAtIndexPath` from within `heightForRowAtIndexPath` leads to recursion – derpoliuk Apr 25 '16 at 11:37
1

I have gotten this to work using proper constraints where the label has top and bottom constraints set and returning the UITableViewAutomaticDimension in the heightForRowAt like this

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

In my case I had several labels inside a stack view and I had to set the stack view top and bottom to the contentView in order for the cell to grow.

Maria
  • 4,471
  • 1
  • 25
  • 26
  • I'll look into this. I think this is probably the right approach for 2018. :) I know I had very little luck with autolayout to size cells in the past, but this was due to iOS 9 which I can finally drop. – Steven Fisher May 02 '18 at 22:25