views:

389

answers:

3

Question

How can you detect when the Table View is done drawing the cells?

Issue

I got two labels within the contentView of an UITableViewCell. The size of these labels are dynamic. I was able to do so by subclassing UITableViewCell, in the drawRect method I adjust the frames of the two labels depending on their content. Now I want to align all the second labels.

My Thoughts in Steps

  1. Determine the content in the table view and let it load automatically.
  2. Run through the table view cells and determine the x position of the second label within the UITableViewCell that is the furtherest away.
  3. Store this x position and when any cell is drawn use this x position to place the second label.

The problem is that if I use the following code:

for (int row = 0; row < [self.tableView numberOfRowsInSection:section]; row++) {
    UITableViewCustomCell *cell = (UITableViewCustomCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:0]];
    NSLog ([cell.labelTwo description]);        
}

The second label has not yet been drawn, meaning I can't determine the size of the frame and thus can not find the proper x position to align all second labels.

I have tried subclassing the UITableViewController and looking at events such as viewDidLoad and viewDidAppear unfortunatly also in these events the cells aren't drawn yet.

What I Want ...

What I want is for the table view to draw the cells at least once so I can determine the sizes of the labels within the table view cell. I thought to accomplish this by looping through all the cells with cellForRow, but although it successfully returns the cell the content is not drawn yet meaning the frame remains with a width of zero.

Does anyone have a solution?

Thanks in advance,

Mark

A: 

I think what you need to do is to add a viewController to the have the UITableViewController control the UITableViewCell itself so that you can capture the events of the labels loading. The viewController will have references to both labels so it can adjust them accordingly in response to -viewDidAppear.

I've never done this but a UITableViewCell is a view like any other so you should be able to set up a controller for it. You might need to manually activate the controller since you have no navigation controller to do it for you in this context.

TechZen
The docs state that UIViewControllers are for full-screen (not counting navbar, tab bar, etc) views. You can bend this rule a little, but having a controller for a UITableViewCell is insane, especially because UITableView creates and destroys them on the fly."Note: You should not use view controllers to manage views that fill only a part of their window—that is, only part of the area defined by the application content rectangle. If you want to have an interface composed of several smaller views, embed them all in a single root view and manage that view with your view controller."
lawrence
Yes, it would be better to have the UITableViewController controlling the cells. I'll change the answer to reflect that.
TechZen
+2  A: 

Try calling sizeWithFont: on the contents of these labels to get the max width before you draw anything. You should be able to use it later in your cellForRowAtIndexPath: to adjust the width as you need.

I would recommend you reconsider using UITableViewCellStyleValue2 cells instead and attempt to configure the textLabel and detailTextLabel. I had a similar situation and this is how I did it.

ahmadabdolkader
+1  A: 

First off, you really ought to just pick an explicit, fixed position at which the first label ends and the second one begins, based on what you know about the minimum and maximum lengths of the text that will be put in those labels. That would eliminate this problem entirely.

But if you want a solution: use the sizeWithFont: method or one of its cousins (see the Xcode docs). Specifically, loop through the values that will go in the first labels, apply sizeWithFont to each, and keep track of the largest width you see. (I'm assuming you have access to the values before they go in the cells; since they're dynamic, they must be passing through the table view controller, no?)

Now you have the value you seek, without having to perform the extremely wasteful operation of creating a bunch of cell objects and never using them for their intended purpose.

lawrence