Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieving a UITableViewCell frame

I've frustrated myself with this question for a couple of days. I'm trying to add a UILabel to a UITableViewCell. I want the UILabel to span the entire width of the cell, minus 5 or 10 on both the right and left sides for looks. My problem is in programmatically determining the size of the cell's frame in which to place the label. No matter which UITableViewStyle I use, the cell.contentVew.frame.size.width value is nowhere near the width of the cell frame itself.

For example, in the table I am constructing, I can achieve my desired result by subclassing UITableViewCell and creating a UILabel with a manually determined width (through just trial and error) by:

CGRectMake(10, 12, 397, self.contentView.frame.size.height);

But it's that 397 number that's vexing me. I want a way to programmatically determine what it should be for any width table or style. This should be a simple process by just determining the width of the entire frame of the cell and then subtracting 10 or 20 so the UILabel's edges don't actually touch the edge of the cell.

However, if I set the tableViewStyle to UITableViewStyleDefault and then try:

NSLog(@"Width: %f", self.contentView.frame.size.width);

I get 320. If I set the style to any of the other three styles, the returned number is 302. Even the 320 number isn't anywhere near the width of the cell frame (as with my manually determined number of 397).

What value do I need to access that will return the entire width of the cell's drawing frame? I'm sure, as with most vexing problems, the solution will make me want to slap myself on the forehead, but I'm to the point where I'm ready for it now.

EDIT for more info:

One clarification to anyone interested. This question of mine pertains primarily to a Grouped style table. For a plain style, the answer to my question above can be determined simply in the cellForRowAtIndexPath method by:

CGFloat cellWidth = [tableView rectForRowAtIndexPath:indexPath].size.width;

The problem I'm having is that the rectForRowAtIndexPath method returns the width of the frame in which the cell is drawn, which is fine for a plain style table since the cell width is the entire width of the frame. However, in a grouped table, the width of the cell is less than the width of the frame in which it is drawn, so this method will return a number that is quite a bit wider than the width of the cell. It's possible that the width of the cell in a grouped table style is a fixed number less than the width of the table frame, so this might be the way to solve the problem. I'll investigate that and answer my own question here if that's the case.

like image 453
Chris Avatar asked Oct 04 '11 19:10

Chris


2 Answers

I have determined my own answer, and I hope it helps anyone faced with the same issue. The calculation of the margin of a grouped tableView I found on this StackOverflow answer.

This code will provide a label within a tableView cell that spans the cell with a margin between the two edges of the cell, and centered vertically within the cell.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    UILabel *label;
    CGFloat groupedStyleMarginWidth, tableViewWidth;
    UIFont *labelFont = [UIFont boldSystemFontOfSize:17.0]; // Set to whatever you like
    NSString *labelText = @"Test String";

    // Calculate the margin between the cell frame and the tableView
    // frame in a grouped table view style.
    tableViewWidth = tableView.frame.size.width;
    if (tableView.style == UITableViewStyleGrouped) {
        if (tableViewWidth > 20)
            groupedStyleMarginWidth = (tableViewWidth < 400) ? 10 : MAX(31, MIN(45, tableViewWidth*0.06));
        else
            groupedStyleMarginWidth = tableViewWidth - 10;
    }
    else
        groupedStyleMarginWidth = 0.0;

    if (cell == nil) {
        CGRect tableViewRect;
        CGRect labelRect;
        CGFloat x, y, w, h, labelMargin;

        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

        // Retrieve the rect of the table view.
        tableViewRect = [tableView rectForRowAtIndexPath:indexPath];

        // Set whatever margin around the label you prefer.
        labelMargin = 10;

        // Determine rect values for the label.
        x = tableRect.origin.x + labelMargin;

        // Calculate width of label
        w = tableRect.size.width - (groupedStyleMargin * 2) - (labelMargin * 2);

        // Calculate height of table based on font set earlier.
        h = [labelText sizeWithFont:font].height;

        // Calculate y position for the label text baseline to center
        // vertically within the cell.
        y = (tableRect.origin.y / 2) - (h / 4);

        labelRect = CGRectMake(x, y, w, h);

        label = [[UILabel alloc] initWithFrame:labelRect];
        label.text = labelText;
        label.tag = 0;
        [cell.contentView addSubview:stepLabel];
        [label release];
    }
    else {
        label = (UILabel *)[cell viewWithTag:0];
    }
like image 56
Chris Avatar answered Oct 19 '22 23:10

Chris


Sounds like this would best be handled by auto layout constraints nowadays.

like image 41
ShowPony Avatar answered Oct 20 '22 00:10

ShowPony