I have the following setup: UITableView with custom UITableViewCell implementation. In each cell I have a UILabel and a UIButton. When the table is first displayed, in each of the cells, the UILabel has the number of lines set to 1 and all cells have fixed height (60 px in my case). When the button in the cell is tapped, then the UILabel's number of lines is set to 0 and word wrap is turned on, effectively expanding the table cell.
Now, the issue is that only the implementation of UITableViewCell knows whether the label is expanded or not - and thus what the cell height should be. However the owner file is the table's datasource.
I can't get may head around how to set this up. Any ideas are appreciated.
Update here are extracts from my code
In the custom UITableViewCell implementation:
- (float)requiredHeight
{
if(isFull)
{
CGSize labelSize = [LblTitle.text sizeWithFont: [LblContent font]
constrainedToSize: CGSizeMake(300.0f, 300.0f)
lineBreakMode: UILineBreakModeTailTruncation];
return 42.0f + labelSize.height;
}
else
{
return 60.0f;
}
}
In owner file (UITableViewDelegate):
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
OOCommentCell *cell = (OOCommentCell*)[tableView cellForRowAtIndexPath:indexPath];
return [cell requiredHeight];
}
However this results randomly in an infinite loop or in BAD_ACCESS_EXCEPTION.
OK, after some struggling, here's what I ended up with, which kind of works.
- I created a simple class to contain information related to one cell:
@interface CommentInfo : NSObject
{
int ID;
NSString *Name;
NSString *Date;
NSString *Content;
BOOL IsFull;
float Height;
}
@property (readonly) int ID;
@property (readonly) NSString *Name;
@property (readonly) NSString *Date;
@property (readonly) NSString *Content;
@property (readwrite, assign) float Height;
@property (readwrite, assign) BOOL IsFull;
- (id)initWithID:(int)_id withName:(NSString *)_name withDate:(NSString *)_date withText:(NSString *)_text;
@end
Don't worry too much about all the properties - the most important one is the Height
.
In my controller (which is also the delegate for the table view), I keep the data as an NSMutableArray
of pointers to objects of type CommentInfo
.
In cellForRowAtIndexPath
I get the corresponding pointer and pass it to the custom cell implementation during construction, where it is stored. I also set self
as a delegate to the cell.
In the custom cell implementation, when I need to expand/change the height, I update the Height
property in the CommentInfo
object and call a method in the delegate to update the display.
When this updateDisplay
method is called, I simple do the following:
[CommentsTable beginUpdates];
[CommentsTable endUpdates];
- In
heightForRowAtIndexPath
method, I retrieve the corresponding pointer to CommentInfo
and read the Height
property. As the pointer is the same between the controller and the cell, any changes to this property will be visible in both classes.
Job done.
Implement the method UITableViewDelegate – tableView:heightForRowAtIndexPath: in your table delegate. If you want to define height on a per-cell basis, you could 'forward' this call to the cell's class by calling your own tableView:cellForRowAtIndexPath: method in tableView:heightForRowAtIndexPath.
Update: Implemented in code. The error was caused by an incorrect method signature in the delegate calling tableView:cellForRowAtIndexPath.
In the custom UITableViewCell implementation:
- (CGFloat)requiredHeight
{
if(isFull)
{
CGSize labelSize = [LblTitle.text sizeWithFont: [LblContent font]
constrainedToSize: CGSizeMake(300.0f, 300.0f)
lineBreakMode: UILineBreakModeTailTruncation];
return 42.0f + labelSize.height;
}
else
{
return 60.0f;
}
}
In owner file (UITableViewDelegate):
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
OOCommentCell *cell = (OOCommentCell*)[self tableView:tableView cellForRowAtIndexPath:indexPath];
return [cell requiredHeight];
}