Simon say’s Project-D UITableViewCells autosize based on text height in MonoTouch. Here’s how!
While building the main story view in Project-D which uses a UITableView I needed to have each cell dynamically snap in their height based on the height of the content, which in this case is text.
To do this you must implement UITableViewDelegate along with UITableViewDataSource.
When implementing UITableViewDelegate the key override is GetHeightForRow(). This method lets us return what the height is for a particular row.
I’m doing 2 key things for performance reasons in GetHeightForRow() which are:
- Caching a font instance which represents the font I am using on the UITableViewCell
- Caching the cell height in my model, so that I only ever do this calculation once for a particular UITableViewCell
Basically what I am doing here is giving the measuring API a constraint width wise, and it will give me back a size of how high the text with this particular font consumes:
public class StoryViewTableController : UITableViewDelegate
{
private static UIFont font = null;
private StoryViewController viewController = null;
public StoryViewTableController(StoryViewController viewController)
{
this.viewController = viewController;
if (font == null)
font = UIFont.FromName("Helvetica", 14.0f);
}
public override float GetHeightForRow(UITableView tableView, NSIndexPath indexPath)
{
Story story = viewController.DataSource.Stories.Stories[indexPath.Row];
if (story.CellSize.Height == 0)
{
story.Title = story.Title.Trim();
story.Description = story.Description.Trim();
story.TitleSize = tableView.StringSize(story.Title, font, new SizeF(237.0f, 1000.0f), UILineBreakMode.WordWrap);
story.DescriptionSize = tableView.StringSize(story.Description, font, new SizeF(237.0f, 1000.0f), UILineBreakMode.WordWrap);
SizeF sizeTotal = new SizeF(237.0f, story.TitleSize.Height + story.DescriptionSize.Height + 20);
story.CellSize = sizeTotal;
if (story.CellSize.Height < 108)
story.CellSize = new SizeF(story.CellSize.Width, 108);
}
return story.CellSize.Height;
}
}
In my UITableViewDataSource I am doing the same technique I showed in the tutorial
Let’s Build A Custom UITableViewCell and applying the new sizes that I store in the model to the cell itself.
public override UITableViewCell GetCell(UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
UITableViewCell cell = null;
StoryCellController controller = null;
cell = tableView.DequeueReusableCell("StoryCell");
if (cell == null)
{
controller = new StoryCellController();
NSBundle.MainBundle.LoadNib("StoryCellController", controller, null);
cell = controller.Cell;
cell.Tag = Environment.TickCount;
cellControllers.Add(cell.Tag, controller);
}
else
{
controller = cellControllers[cell.Tag];
}
Story story = stories.Stories[indexPath.Row];
controller.Title = story.Title.Trim();
controller.Description = story.Description.Trim();
// Sizing the cell.
RectangleF rectCell = cell.Frame;
rectCell.Height = story.CellSize.Height;
cell.Frame = rectCell;
// Sizing the background image.
RectangleF rectImageBackground = controller.ImageBackground.Frame;
rectImageBackground.Height = story.CellSize.Height;
controller.ImageBackground.Frame = rectImageBackground;
// Sizing the LabelTitle.
controller.LabelTitle.Frame = new RectangleF(
new PointF(
controller.LabelTitle.Frame.X,
controller.LabelTitle.Frame.Y),
story.TitleSize);
// Sizing the LabelDescription.
controller.LabelDescription.Frame = new RectangleF(
new PointF(
controller.LabelDescription.Frame.X,
story.TitleSize.Height + 10),
story.DescriptionSize);
return cell;
}
Hopefully this helps people out. As always you can find me on Twitter via @simongui and I appreciate any retweets!


thnk great job.
would you share source code
hi, why are you applying a height for the cell in the GetCell method? the height is already set by the overridden delegate, is it?
thanks for sharing information!
filip
Just wanted to say thank you for sharing what you've learned. It's been invaluable as I plod along behind your path.
Great tip. Trying to follow this but wondering where you get these from:
- story.CellSize
- story.TitleSize
- story.CellSize.Height
- story.TitleSize.Height
- story.DescriptionSize
- story.DescriptionSize.Height
Would be more helpful to post a working sln for download.
Managed t work this out, supurb bit of work!
I realised that you store the objects as SizeF types in your data class. Once i did this it all slotted into place. The only other thing I had to do was set the labels as Public in my XIB designer file.