views:

780

answers:

1

I am using the code below to put together my UITableView. The Cell height allows the first three rows to show in the table without scrolling. Everything is fine with those first three rows. But as soon as I scroll down past the original first three rows, the image in the myImage inherits the width of cells in the first three rows and does not resize according to the value extracted from the array based on indexPath.row.

The cell is obviously being reused from the else statement from the originally painted cells but I need to figure out a way to allow the myImage width to vary for each row.

Any help is Greatly Appreciated! lq

- (UITableViewCell *)tableView:(UITableView *)tableView
     cellForRowAtIndexPath:(NSIndexPath *)indexPath {

const NSInteger LABEL_TAG = 1001;
const NSInteger IMAGE_TAG = 1002;

UILabel *myLabel;
UIImageView *myImage;

static NSString *CellIdentifier = @"Cell";

UITableViewCell *cell = [myTableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {

    // Create the cell

    cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero
                        reuseIdentifier:CellIdentifier]
                        autorelease];

    // Constant values

    const CGFloat LABEL_HEIGHT = 20;
    const CGFloat LABEL_WIDTH = 140;
    const CGFloat LABEL_INDENT = 1;
    const CGFloat LABEL_TOP = 0.065 * myTableView.rowHeight;

    // Create the label;

    myLabel = [[[UILabel alloc] initWithFrame:
            CGRectMake(
                LABEL_INDENT,
                LABEL_TOP  + LABEL_HEIGHT,
                LABEL_WIDTH,
                LABEL_HEIGHT)]
            autorelease];

    [cell.contentView addSubview:myLabel];

    // Configure the label

    myLabel.tag = LABEL_TAG;
    myLabel.backgroundColor = [UIColor clearColor];
    myLabel.textColor = [UIColor blueColor];
    myLabel.font = [UIFont systemFontOfSize:[UIFont labelFontSize] - 3];
    myLabel.textAlignment = UITextAlignmentRight;

    // Create the image (NOTE: THIS IS THE PROBLEMATIC PART)

    // Extract the width for the image based on an array value for each row:

    int xValue = [[myArray objectAtIndex:(indexPath.row)]intValue]; 
    float xLength = (float)xValue / 100;

    myImage = [[[UIImageView  alloc] initWithFrame:
                CGRectMake(
                    LABEL_INDENT + 53,              // This places the image to the right of the label
                    LABEL_TOP  + LABEL_HEIGHT,
                    xLength * LABEL_WIDTH,          

// This is where the width of each row is adjusted LABEL_HEIGHT] autorelease];

    [cell.contentView addSubview:myImage];

    myImage.contentMode = UIViewContentModeLeft;
    myImage.image = [UIImage imageNamed:@"ProgressBar.png"];
    myImage.clipsToBounds = YES;

} else {

    // Re-use cells

    myLabel = (UILabel *)[cell viewWithTag:LABEL_TAG];
    myImage = (UIImageView *)[cell viewWithTag:IMAGE_TAG];  
}

return cell;

}
+1  A: 

Hi

The above reuses the cells, as you draw attention to in your comments, but; after finding a cached cell you do the setup again, not matter if the cell is old or new.

The UITableViewCell is a "two-parter", the first time a cell is referenced it is instantiated and build, all the subsequent times it is referenced it should only be updated. (a cell is referenced each time it is scrolled onto the screen or the tableview is reloaded etc. this happens often so to save CPU time it is also best not to do the same setup again and again).

So, try approaching it like this instead:

- (void) configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {

    UILabel *settingText = [ISInterfaceElement getLabel:Headline]; //Opps... ISInterfaceElement is my custom class. All it does is return a UILabel with settings that comply for a Headline label, according to an enum in the header.
    [settingText setFrame:CGRectMake(0.0f, 15.0f, 320.0f, 20.0f)];
    [settingText setTextAlignment:UITextAlignmentCenter];
    [settingText setTag:SETTINGS_LABEL];
[cell addSubview:settingText];
    UIView *background = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 50.0f)];
    [cell addSubView:background]; //added
    [background release]; //added

[cell setSelectionStyle:UITableViewCellSelectionStyleNone];     
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {       
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
        [self configureCell:cell atIndexPath:indexPath];
    }


    [(UILabel*)[cell viewWithTag:SETTINGS_LABEL] setText:@"Settings…"];

    return cell;
}

So the cellForRowAtIndexPath call the configureCell method if it needs a new cell setup, else it simply updates the cell with the correct value from the model (usually [someArray objectAtIndex:indexPath.row] but in my case just a string.

So send along any parameter(height) you need the configureCell method to know to be able to build your cell, and do all the building in that method and all the updating in cellForRowAtIndex.

Hope it makes sense:)

RickiG
Thank you SO much for your quick response and getting me over this hurdle. I just rebuilt it following your example and it's working splendidly.Here's the additional element for anyone else looking for a solution to this type of design element:...// Deal with Label Text in Cell:[(UILabel*)[cell viewWithTag:SETTINGS_LABEL] setText:@"Settings…"];// Deal with Variable Image Width in Cell:[(UIImageView*)[cell viewWithTag:IMAGE_TAG] setFrame:CGRectMake((0.0f, 15.0f, xLength * LABEL_WIDTH, 20.0f)];
Lauren Quantrell
You are welcome. Consider marking the question as answered ;)
RickiG
When you `alloc` the `background` variable, you leak memory.
Shaggy Frog
@Shaggy, Thanks, You are, of course, correct. I also forgot to add the background view to the cell...
RickiG