I am trying to learn Obj-C and iOS programming, but am still very new. I decided to try and make a simple Reddit client application. I am trying to display the front page po
For new iOS 8 there is a new way to make this simple.
There is new a parameter that calculates your cell height with respect of your auto layout constraints. This is UITableViewAutomaticDimension
. You can use it in the viewWillAppear
method of your view controller.
Objective C:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.tableView.estimatedRowHeight = 70.0; // for example. Set your average height
self.tableView.rowHeight = UITableViewAutomaticDimension;
[self.tableView reloadData];
}
Swift:
override func viewWillAppear(animated: Bool) {
self.tableView.estimatedRowHeight = 70 // for example. Set your average height
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.reloadData()
}
Work nice and as you want at your example. As for me, I add height things in viewDidLoad
and left in viewWillAppear
only reloadData(). There is also useful source.
From documentation: The default value of rowHeight is UITableViewAutomaticDimension.
I leave the code as it is, for now, but keep in mind that you don't need to set row height in iOS 8+.
The main thing you need to do is to set all constraints explicitly e.g. to the leading, trailing, top and bottom. Try it first, without adding any lines of code above.
In your tableview heightForRowAtIndexPath delegate method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 2) {
Message *aMessage = [customTableViewArray objectAtIndex:indexPath.row];
if ( [aMessage.msgBody length] <= 0 )
aMessage.msgBody = @" ";
CGSize constraint = CGSizeMake(450, 40000.0f);
CGSize size = [aMessage.msgBody sizeWithFont:[UIFont fontWithName:@"Helvetica" size:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeCharacterWrap];
size.height = MAX(size.height,36);
return 136+size.height;
} else if(indexPath.row > 1) {
Message *aMessage = [customTableViewArray objectAtIndex:indexPath.row];
if ( [aMessage.msgBody length] <= 0 )
aMessage.msgBody = @" ";
CGSize constraint = CGSizeMake(450, 40000.0f);
CGSize size = [aMessage.msgBody sizeWithFont:[UIFont fontWithName:@"Helvetica" size:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeCharacterWrap];
size.height = MAX(size.height,36);
return 100+size.height;
} else {
return 146;
}
}
I apologize, I had only included part of the code. This is the whole thing. So basically if the message is empty it makes it one size. Then in the else if part of the statement, it gets the size of the message and bases the cell size on that message size.
You should check out the documentation reference for
-[UITableViewDelegate tableView:heightForRowAtIndexPath:]
Essentially, you will need to measure the text yourself in order to return the correct dimensions for each table row. If they're simple NSStrings
, which they appear to be from your screenshot, you can use the NSString UIKit Additions to measure them, e.g.
-[NSString sizeWithFont:constrainedToSize:]
Where the constrained size could have infinite height but the width of your table cell's content view.
If they are attributed strings, there is a similar method in the NSAttributedString UIKit additions called boundingRectWithSize:options:context:
It happens that my app TidBITS News does exactly what you're describing. And I believe it was one of the first apps to figure out how to do it; at least, at the time I wrote it, I knew of no other apps that did this. I published my method in my Programming iOS 4 book, and since then it has become commonplace (though I'm not saying everyone got it from me; there is basically only one sensible way to approach it).
Here's the explanation from the current version of my book:
http://www.apeth.com/iOSBook/ch21.html#_variable_row_heights
As you can see, the trick is to work out the heights of all the rows in advance by calling sizeWithFont:constrainedToSize:
on the label with the data it will contain in each row, and doing the necessary math. This is because tableView:heightForRowAtIndexPath:
is going to be called up front, over and over, to determine the heights of every row, before you are asked for the data.
Then, when you are asked for cellForRowAtIndexPath:
, you use the results you derived in advance in order to lay out the cell within the height you previously calculated.
On Github I've also got a downloadable complete project example that you can read and run; it shows you how to do it with constraints (iOS 6 and later only). Look for the ch21
example with variableHeights
in its name.