[ios] Custom Cell Row Height setting in storyboard is not responding

I am trying to adjust the cell height for one of the cells on my table view. I am adjusting the size from the "row height" setting inside the "size inspector" of the cell in question. When I run the app on my iPhone the cell has the default size set from the "row size" in the table view.

If I change the "row size" of the table view then the size of all cells changes. I do not want to do that as I want a custom size only for one cell. I have seen a lot of posts that have a programmatic solution to the problem, but I would prefer to do it through storyboard, if that is possible.

This question is related to ios uitableview ios5 storyboard xcode4.2

The answer is


I think it is a bug.

Try adjust height not by Utility inspector but by mouse drag on the storyboard directly.

I solved this problem with this method.


Open the storyboard in the XML view and try to edit the rowHeight attribute of the wanted element.

It worked for me when I tried to set custom rowHeight for my prototyped row. It's not working via inspector, but via XML it works.


For dynamic cells, rowHeight set on the UITableView always overrides the individual cells' rowHeight.

This behavior is, IMO, a bug. Anytime you have to manage your UI in two places it is prone to error. For example, if you change your cell size in the storyboard, you have to remember to change them in the heightForRowAtIndexPath: as well. Until Apple fixes the bug, the current best workaround is to override heightForRowAtIndexPath:, but use the actual prototype cells from the storyboard to determine the height rather than using magic numbers. Here's an example:

- (CGFloat)tableView:(UITableView *)tableView 
           heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    /* In this example, there is a different cell for
       the top, middle and bottom rows of the tableView.
       Each type of cell has a different height.
       self.model contains the data for the tableview 
    */
    static NSString *CellIdentifier;
    if (indexPath.row == 0) 
        CellIdentifier = @"CellTop";
    else if (indexPath.row + 1 == [self.model count] )
        CellIdentifier = @"CellBottom";
    else
        CellIdentifier = @"CellMiddle";

    UITableViewCell *cell = 
              [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    return cell.bounds.size.height;
}

This will ensure any changes to your prototype cell heights will automatically be picked up at runtime and you only need to manage your UI in one place: the storyboard.


There are actually two places where you need to change to row height, first the cell (you already did change that) and now select the Table View and check the Size Inspector


You can get height of UITableviewCell (in UITableviewController - static cells) from storyboard with help of following lines.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
   CGFloat height = [super tableView:tableView heightForRowAtIndexPath:indexPath];

    return height;
}

For dynamic cells, rowHeight set on the UITableView always overrides the individual cells' rowHeight. Just calculate the dynamic height if the content inside the row.


The only real solution I could find is this

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = ...; // Instantiate with a "common" method you'll use again in cellForRowAtIndexPath:
    return cell.frame.size.height;
}

This works and allows not to have an horrible switch/if duplicating the logic already in the StoryBoard. Not sure about performance but I guess when arriving in cellForRow: the cell being already initalized it's as fast. Of course there are probably collateral damages here, but it looks like it works fine for me here.

I also posted this here: https://devforums.apple.com/message/772464

EDIT: Ortwin Gentz reminded me that heightForRowAtIndexPath: will be called for all cells of the TableView, not only the visible ones. Sounds logical since iOS needs to know the total height to be able to show the right scrollbars. It means it's probably fine on small TableViews (like 20 Cells) but forget about it on a 1000 Cell TableView.

Also, the previous trick with XML: Same as first comment for me. The correct value was already there.


Added as a comment, but posting as an answer for visibility:

There seems to also be an issue if you initially setup a table view as "static cells" and then change it to "dynamic prototypes." I had an issue where even the delegate method for heightForRowAtIndexPath was being ignored. I first resolved it by directly editing the storyboard XML, then finally just rebuilt the storyboard scene from scratch, using dynamic prototypes from the start.


You can use prototype cells with a custom height, and then invoke cellForRowAtIndexPath: and return its frame.height.:.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [self tableView:tableView
                    cellForRowAtIndexPath:indexPath];
    return cell.frame.size.height;
}

If you use UITableViewController, implement this method:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

In the function of a row you can choose Height. For example,

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == 0) {
       return 100;
    } 
    else {
       return 60;
    }
}

In this exemple, the first row height is 100 pixels, and the others are 60 pixels.

I hope this one can help you.


If you want to set a static row height, you can do something like this:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return 120;
}

I've built the code the various answers/comments hint at so that this works for storyboards that use prototype cells.

This code:

  • Does not require the cell height to be set anywhere other than the obvious place in the storyboard
  • Caches the height for performance reasons
  • Uses a common function to get the cell identifier for an index path to avoid duplicated logic

Thanks to Answerbot, Brennan and lensovet.

- (NSString *)cellIdentifierForIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = nil;

    switch (indexPath.section)
    {
        case 0:
            cellIdentifier = @"ArtworkCell";
            break;
         <... and so on ...>
    }

    return cellIdentifier;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];
    static NSMutableDictionary *heightCache;
    if (!heightCache)
        heightCache = [[NSMutableDictionary alloc] init];
    NSNumber *cachedHeight = heightCache[cellIdentifier];
    if (cachedHeight)
        return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = [self cellIdentifierForIndexPath:indexPath];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];

    <... configure cell as usual...>

One other thing you can do is to go to your Document Outline, select the table view that your prototype cell is nested. Then on the Size Inspector, change your table view Row Height to your desired value and uncheck the Automatic box.


Given that I did not find any solution to this problem through Interface Builder, I decided to post a programmatic solution to the problem in Swift using two dynamic cells, even though the initial question asked for a solution through Interface Builder. Regardless I think it could be helpful for the Stack Overflow community:

    import UIKit

    enum SignInUpMenuTableViewControllerCellIdentifier: String {
       case BigButtonCell = "BigButtonCell"
       case LabelCell = "LabelCell"
    }

    class SignInUpMenuTableViewController: UITableViewController {
            let heightCache = [SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell : CGFloat(50),
                              SignInUpMenuTableViewControllerCellIdentifier.LabelCell : CGFloat(115)]

    private func cellIdentifierForIndexPath(indexPath: NSIndexPath) -> SignInUpMenuTableViewControllerCellIdentifier {
        if indexPath.row == 2 {
            return SignInUpMenuTableViewControllerCellIdentifier.LabelCell
        } else {
            return SignInUpMenuTableViewControllerCellIdentifier.BigButtonCell
        }
    }

   override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
       return self.heightCache[self.cellIdentifierForIndexPath(indexPath)]!
   }

   ...

  }

I have recently been wrestling with this. My issue was the solutions posted above using the heightForRowAtIndexPath: method would work for iOS 7.1 in the Simulator but then have completely screwed up results by simply switching to iOS 8.1.

I began reading more about self-sizing cells (introduced in iOS 8, read here). It was apparent that the use of UITableViewAutomaticDimension would help in iOS 8. I tried using that technique and deleted the use of heightForRowAtIndexPath: and voila, it was working perfect in iOS 8 now. But then iOS 7 wasn't. What was I to do? I needed heightForRowAtIndexPath: for iOS 7 and not for iOS 8.

Here is my solution (trimmed up for brevity's sake) which borrow's from the answer @JosephH posted above:

- (void)viewDidLoad {
    [super viewDidLoad];

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

    // ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
        return UITableViewAutomaticDimension;

    } else {
        NSString *cellIdentifier = [self reuseIdentifierForCellAtIndexPath:indexPath];
        static NSMutableDictionary *heightCache;
        if (!heightCache)
            heightCache = [[NSMutableDictionary alloc] init];
        NSNumber *cachedHeight = heightCache[cellIdentifier];
        if (cachedHeight)
            return cachedHeight.floatValue;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    CGFloat height = cell.bounds.size.height;
    heightCache[cellIdentifier] = @(height);
    return height;
    }
}

- (NSString *)reuseIdentifierForCellAtIndexPath:(NSIndexPath *)indexPath {
    NSString * reuseIdentifier;
    switch (indexPath.row) {
        case 0:
            reuseIdentifier = EventTitleCellIdentifier;
            break;
        case 2:
            reuseIdentifier = EventDateTimeCellIdentifier;
            break;
        case 4:
            reuseIdentifier = EventContactsCellIdentifier;
            break;
        case 6:
            reuseIdentifier = EventLocationCellIdentifier;
            break;
        case 8:
            reuseIdentifier = NotesCellIdentifier;
            break;
        default:
            reuseIdentifier = SeparatorCellIdentifier;
            break;
    }

    return reuseIdentifier;
}

SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0") is actually from a set of macro definitions I am using which I found somewhere (very helpful). They are defined as:

#define SYSTEM_VERSION_EQUAL_TO(v)                  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v)              ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v)  ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v)                 ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v)     ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)

The same problem occurred when working on XCode 9 using Swift 4.

Add AutoLayout for the UI elements inside the Cell and custom cell row height will work accordingly as specified.


If you're using swift , use like this. Don't Use storyboard to select row height. Programmatically set table row height like this,

 func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    if indexPath.row == 0 || indexPath.row == 1{
        let cell = self.tableView.dequeueReusableCellWithIdentifier("section1", forIndexPath: indexPath) as! Section1TableViewCell
        self.tableView.rowHeight = 150
        cell.label1.text = "hiiiiii"
        cell.label2.text = "Huiiilllllll"
        return cell

    } else {

        let cell = self.tableView.dequeueReusableCellWithIdentifier("section2", forIndexPath: indexPath) as! Section2TableViewCell
        self.tableView.rowHeight = 60
        cell.label3.text = "llll"
        return cell
    }

}

Examples related to ios

Adding a UISegmentedControl to UITableView Crop image to specified size and picture location Undefined Symbols error when integrating Apptentive iOS SDK via Cocoapods Keep placeholder text in UITextField on input in IOS Accessing AppDelegate from framework? Autoresize View When SubViews are Added Warp \ bend effect on a UIView? Speech input for visually impaired users without the need to tap the screen make UITableViewCell selectable only while editing Xcode 12, building for iOS Simulator, but linking in object file built for iOS, for architecture arm64

Examples related to uitableview

Adding a UISegmentedControl to UITableView make UITableViewCell selectable only while editing How to fix Error: this class is not key value coding-compliant for the key tableView.' UITableView example for Swift Swift - how to make custom header for UITableView? How to insert new cell into UITableView in Swift How to detect tableView cell touched or clicked in swift Dynamic Height Issue for UITableView Cells (Swift) UIButton action in table view cell How to get the indexpath.row when an element is activated?

Examples related to ios5

How to select Multiple images from UIImagePickerController How to get root view controller? Adding Image to xCode by dragging it from File Code signing is required for product type 'Application' in SDK 'iOS5.1' How to Implement Custom Table View Section Headers and Footers with Storyboard Objective-C ARC: strong vs retain and weak vs assign Custom Cell Row Height setting in storyboard is not responding How do I deserialize a JSON string into an NSDictionary? (For iOS 5+) What is the iOS 5.0 user agent string? "Application tried to present modally an active controller"?

Examples related to storyboard

How to make a simple rounded button in Storyboard? Outlets cannot be connected to repeating content iOS creating custom tableview cells in swift How to change Navigation Bar color in iOS 7? How can I switch views programmatically in a view controller? (Xcode, iPhone) How can I load storyboard programmatically from class? What is the difference between Modal and Push segue in Storyboards? Load view from an external xib file in storyboard Perform Segue programmatically and pass parameters to the destination view Custom Cell Row Height setting in storyboard is not responding

Examples related to xcode4.2

Custom Cell Row Height setting in storyboard is not responding