I have seen this question asked many times but astoundingly, I have not seen a consistent answer, so I will give it a try myself:
If you have a tableview containing
So, I think you can do this without having to create your cells all at once (which, as you suggest, is wasteful and also probably impractical for a large number of cells).
UIKit adds a couple of methods to NSString, you may have missed them as they're not part of the main NSString documentation. The ones of interest to you begin:
- (CGSize)sizeWithFont...
Here is the link to the Apple docs.
In theory, these NSString additions exist for this exact problem: to figure out the size that a block of text will take up without needing to load the view itself. You presumably already have access to the text for each cell as part of your table view datasource.
I say 'in theory' because if you're doing formatting in your UITextView your mileage may vary with this solution. But I'm hoping it will get you at least part way there. There's an example of this on Cocoa is My Girlfriend.
The best implementation of this that I've seen is the way the Three20 TTTableView classes do it.
Basically they have a class derived from UITableViewController that delegates the heightForRowAtIndexPath:
method to a class method on a TTTableCell class.
That class then returns the right height, invariably by doing the same sort of layout calculations as you do in the draw methods. By moving it to the class it avoids writing code that depends on the cell instance.
There's really no other option - for performance reasons the framework won't create cells before asking for their heights, and you don't really want to do that either if there could be a lot of rows.
Really good question: looking for more insight on this as well.
Clarifying the issue:
Some of the solutions are surprisingly simple/effective:
solution 1: force the heightForRowAtIndexPath to calculate the the cell's specs. Massimo Cafaro Sept 9th
solution 2: do a first pass "standard size" for the cells, cache results when you do have cell heights, then reload the table using the new heights - Symmetric
solution 3: the other interesting answer seems to be the involving three20 but based on the answer it seems that there isn't a cell drawn in storyboard/xib which would make this "problem" much easier to solve.
as i searched over and over about this topic, finally this logic came to my thought. a simple code, but maybe not efficient enough, but so far it's the best i can find.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary * Object=[[NSDictionary alloc]init];
Object=[Rentals objectAtIndex:indexPath.row];
static NSString *CellIdentifier = @"RentalCell";
RentalCell *cell = (RentalCell *)[tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
}
NSString* temp=[Object objectForKey:@"desc"];
int lines= (temp.length/51)+1;
//so maybe here, i count how many characters that fit in one line in this case 51
CGRect correctSize=CGRectMake(cell.infoLabel.frame.origin.x, cell.infoLabel.frame.origin.y, cell.infoLabel.frame.size.width, (15*lines));
//15 (for new line height)
[cell.infoLabel setFrame:correctSize];
//manage your cell here
}
and here is the rest of the code
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSDictionary * Object=[[NSDictionary alloc]init];
Object=[Rentals objectAtIndex:indexPath.row];
static NSString *CellIdentifier = @"RentalCell";
RentalCell *cells = (RentalCell *)[tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
NSString* temp=[Object objectForKey:@"desc"];
int lines= temp.length/51;
return (CGFloat) cells.bounds.size.height + (13*lines);
}