Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding a UIView to a UITableViewCell via cell.contentView

I have a class called GraphView that extends UIView that basically draws a small little line chart. I need one of these graphs at the top of each section in my UITableView. So I tried by creating a separate cell at the top of one of my sections and then on that cell I did:

[cell.contentView addSubview:graphView];
[graphView release];

But when I scroll down, it's like the graph is glitchy and it shows up in random spots along the UITableView. Anyone have ideas or insight? Is there a better way to incorporate another UIView into the top of each section in my UITableView?

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

    UITableViewCell *cell = [theTableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
    }
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    cell.textLabel.font = [UIFont systemFontOfSize:12];
    cell.detailTextLabel.font = [UIFont systemFontOfSize:12];


    NSString *str1, *str2;
    if(indexPath.section == 0) {
        if(indexPath.row == 0) {

            str1 = @"";
            str2 = @"";

            S7GraphView *graphView = [[S7GraphView alloc] initWithFrame:CGRectMake(10,0,310,100)];
            graphView.dataSource = self;

            NSNumberFormatter *numberFormatter = [NSNumberFormatter new];
            [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
            [numberFormatter setMinimumFractionDigits:0];
            [numberFormatter setMaximumFractionDigits:0];

            graphView.yValuesFormatter = numberFormatter;

            NSDateFormatter *dateFormatter = [NSDateFormatter new];
            [dateFormatter setTimeStyle:NSDateFormatterNoStyle];
            [dateFormatter setDateStyle:NSDateFormatterShortStyle];

            graphView.xValuesFormatter = dateFormatter;

            [dateFormatter release];        
            [numberFormatter release];

            graphView.backgroundColor = [UIColor whiteColor];

            graphView.drawAxisX = NO;
            graphView.drawAxisY = YES;
            graphView.drawGridX = NO;
            graphView.drawGridY = YES;

            graphView.xValuesColor = [UIColor blackColor];
            graphView.yValuesColor = [UIColor blackColor];

            graphView.gridXColor = [UIColor blackColor];
            graphView.gridYColor = [UIColor blackColor];

            graphView.drawInfo = NO;
            graphView.info = @"Load";
            graphView.infoColor = [UIColor whiteColor];


            //When you need to update the data, make this call:

            //[graphView reloadData];

            //S7GraphView *graphView = [[S7GraphView alloc] initWithFrame:CGRectMake(10,0,320,300)];
            //self.graphView.dataSource = self;
            [cell.contentView addSubview:graphView];
            [graphView release];
        }
like image 251
CodeGuy Avatar asked Nov 28 '22 07:11

CodeGuy


2 Answers

A table view works slightly differently than you might expect at first. Basically, only the cells that you see are actually loaded into memory. If you think about it, it makes sense - if you had 10,000 items in your table, all loaded into memory, your app is going run out of memory and crash pretty quickly.

When you scroll, your cells are created in real time. The confusing part: your cells aren't created from scratch, instead iOS just takes a cell that has just left the screen and sends it through

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

again. So, the subview you added to your top cell won't be removed when that cell gets reused further down as you scroll. Short answer: make sure you remove/reset the subview in the function above, this way you will 'reset' any used cells that are being reused further down the table view.

Why does iOS do it this way? Efficiency - basically, it is very expensive to create a tableview cell. Finding the width, color, drawing the shape... + lots more takes a lot of cpu power and time. It is far more efficient to reuse cells each time rather than start from scratch.

So reset only the necessary fields of a cell in your cell creation function. This way, you'll have smooth and quick scrolling, but views/properties of your cell will be reset before the cell is reused.

Confusing at first? Yup. But definitely the better way to do it.

like image 121
Jordan Smith Avatar answered Dec 09 '22 15:12

Jordan Smith


I've solved using tags:

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

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [theTableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
    }
    else{
      [[cell.contentView viewWithTag:500] removeFromSuperview];
    }

    ...

    graphView.tag = 500;
    [cell.contentView addSubview:graphView];

   }
like image 29
intropedro Avatar answered Dec 09 '22 15:12

intropedro