views:

360

answers:

2

I've created a UITableViewController which calculates the height for each row depending on the amount of text it contains. The code to calculate the row height looks like this:

- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
    Message *message = [[[[SessionData sharedSessionData] sessions] objectAtIndex:[indexPath section]] objectAtIndex:[indexPath row]];
    CGSize size = [[message text] sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

    return size.height + (CELL_CONTENT_MARGIN * 2) + 38;
}

As you might notice, I use a separate class as UITableViewDatasource called SessionData. Inside the SessionData class I draw the rows. Each row has a top image, center image (which is repeated depending on the row height) and bottom image. My problem is the following: the center image is drawn a bit darker then the bottom and top images. My guess is this has something to do with the repeating nature of the image, as the top and bottom images are drawn fine. The following code is part of my [tableView:cellForRowAtIndexPath:] message:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }

    // other stuff here, most likely not related to my issue ...

    Message *message  = [[sessions objectAtIndex:[indexPath section]] objectAtIndex:[indexPath row]];       
    CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
    CGSize size = [[message text] sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

    [label setText:[message text]];
    [label setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN - 5.0f, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), size.height)];
    [label setBackgroundColor:[UIColor clearColor]];

    viewTop = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"im1 top.png"]];
    viewMid = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"im1 mid.png"]];
    viewBot = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"im1 bot.png"]];      

    [viewTop setFrame:CGRectMake(0.0, 0.0, 300.0, 17.0)];
    [viewMid setFrame:CGRectMake(0.0, 17.0, 300.0, size.height - 10)];
    [viewBot setFrame:CGRectMake(0.0, 17.0 + size.height - 10, 300.0, 31.0)];

    [viewTop setBackgroundColor:[UIColor clearColor]];
    [viewMid setBackgroundColor:[UIColor clearColor]];
    [viewBot setBackgroundColor:[UIColor clearColor]];  

    [cell.backgroundView setBackgroundColor:[UIColor clearColor]];

    [((UIImageView *)cell.backgroundView) addSubview:viewTop];  
    [((UIImageView *)cell.backgroundView) addSubview:viewMid];  
    [((UIImageView *)cell.backgroundView) addSubview:viewBot];

    [[cell backgroundView] addSubview:label];   

    return cell;
}

My guess is I would need to create a containerView with the total size (width, height) for the top, center and bottom imageViews and add the containerView to the cell, but this didn't seem to work. Anyone have any idea on how to fix this problem?

PLEASE NOTE: My UITableViewController has a gradient as background image. So the top / center / bottom images are drawn on top of the background gradient. Perhaps this is part of the problem as well.

A: 

A few things to note here.

Firstly, there's a lot of processing going on in your cells which will cause very poor scrolling performance on the device. You should make better use of requeuing cells and performing most of the cell setup that's common to all the cells here:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        // Do cell layout in here!
    }

That way cell's and their subviews can be reused instead of recreated every time a cell appears on screen (use the tag properties and viewWithTag: methods of views).

Secondly, you may wish to look at stretchable images.

Thirdly, you will notice much better performance by manually drawing cells. Create a custom view (which you add to the content view), override drawRect:, draw images onto them using UIImage's drawInRect: method. This will speed things up significantly! Draw everything you can because subview laying out is expensive! Also, ensure you use no UIView (inc. UIImageView, UILabel, etc...) transparency if possible, set opaque = YES and set background colors. It is preferable to draw text in drawRect:, using NSString's drawInRect: method which will give the look of a transparent UILabel.

However, if you have VERY few cells, like < 4 or something, then perhaps the drawing method is too much. However, it is still very much advised!

Hope this helps!

Michael Waterfall
A: 

Thanks for your suggestions Michael. I could indeed fix my graphic issues by using the following code:

[bubbleView setImage:[bubble stretchableImageWithLeftCapWidth:165 topCapHeight:30]];

Instead of using 3 separate images to create chat bubbles I can now use 1 image and it stretches gracefully. A very nice suggestion indeed :)

Even though I didn't seem to have much speed issues, I did rewrite my code partially as you suggested, mainly by constructing the main part of the cells in the cell initializer part of the code. I did notice a minor speed improvement, perhaps it's more noticeable on a device (as compared to the simulator).

Currently I still draw my images using ImageView (as you might notice), I'll look at [UIImage drawInRect:] whenever I need more speed in rendering.

Thanks for your suggestions, much appreciated.

Wolfgang Schreurs
Your welcome! Yes I'd suggest testing regularly on a device. The simulator is extremely fast as it's got all your mac's memory and CPU power. If you have a fair number of rows I think you will see slow frame rates when scrolling on the device (compared to say the text messaging app or the iPod app). I initially spent a lot of time just using the simulator and when I eventually tested on the device, everything was **extremely** slow, and I had to rewrite all of my table view code! (granted I used them heavily!) But I've learnt my lesson! Best of luck!
Michael Waterfall