ios 通过 cell.contentView 将 UIView 添加到 UITableViewCell

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4576579/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 18:25:43  来源:igfitidea点击:

Adding a UIView to a UITableViewCell via cell.contentView

iphoneiosuitableview

提问by CodeGuy

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:

我有一个叫做 GraphView 的类,它扩展了 UIView ,它基本上绘制了一个小的折线图。我的 UITableView 中每个部分的顶部都需要这些图表之一。所以我尝试在我的一个部分的顶部创建一个单独的单元格,然后在该单元格上我做了:

[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?

但是当我向下滚动时,它就像图表有问题,它沿着 UITableView 出现在随机位置。任何人都有想法或见解?有没有更好的方法将另一个 UIView 合并到我的 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];
        }

回答by Jordan Smith

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.

表格视图的工作方式与您最初的预期略有不同。基本上,只有您看到的单元格实际加载到内存中。如果您考虑一下,这是有道理的 - 如果您的表中有 10,000 个项目,全部加载到内存中,您的应用程序将耗尽内存并很快崩溃。

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

当您滚动时,您的单元格是实时创建的。令人困惑的部分:您的单元格不是从头开始创建的,而是 iOS 只是将一个刚刚离开屏幕的单元格发送给它

- (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.

为什么iOS会这样做?效率 - 基本上,创建一个 tableview 单元格是非常昂贵的。查找宽度、颜色、绘制形状... + 更多需要大量 CPU 功率和时间。每次重用单元比从头开始要高效得多。

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.

混淆在第一?是的。但绝对是更好的方法。

回答by intropedro

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

   }

回答by Jordan Smith

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.

由于图形视图而不是 UIView,您的情况可能略有不同。但这绝对是它应该是什么样子的基础。

Hope that helps!

希望有帮助!

回答by vikingosegundo

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.

每次tableView:cellForRowAtIndexPath:执行时,您都会添加 GraphView 的另一个实例。结合单元重用,单元对象被重新分配给其他索引路径,这会导致很大的麻烦。

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

你应该只在里面添加子视图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.

您必须单独跟踪或您的 GraphViews。通过将它们添加到以 indexPaths 作为键的 NSDictionary,或者通过继承 UITableViewCell。