开发者

Adding a UIView to a UITableViewCell via cell.contentView

开发者 https://www.devze.com 2023-02-02 15:30 出处:网络
I have a class called GraphView that extends UIView开发者_如何学Go 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 b

I have a class called GraphView that extends UIView开发者_如何学Go 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];
        }


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.


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];

   }


Ok like this:

static NSString *CellIdentifier = @"Cell";   

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

//now remove any subview a reused cell might have:   
[cell.contentView.view removeFromSuperview];   
//and in part of the method, you'll need to create the subview if the cell is in the top row.

if (indexPath.row == 0)
{
    [cell.contentView.view addSubview:graphView.view];
}

It could be slightly different in your case because of the graph view rather than a UIView. But this is definitely the basis of what it should look like.

Hope that helps!


This is, as I thought, a cell-reuse issue:

each time, tableView:cellForRowAtIndexPath: get executed, you add another instance of GraphView. In combination with cell-reuse, where cell-objects get reassigned to other indexPaths, this leads to great trouble.

You should add subviews only inside if (cell == nil).

You'll have to keep track or your GraphViews seperately. Either by adding them to a NSDictionary with the indexPaths as key, or by subclassing UITableViewCell.

0

精彩评论

暂无评论...
验证码 换一张
取 消