iPhone:向 Cell ContentView 添加子视图会在滚动时覆盖单元格文本

Posted

技术标签:

【中文标题】iPhone:向 Cell ContentView 添加子视图会在滚动时覆盖单元格文本【英文标题】:iPhone: Adding subviews to Cell ContentView overwrites cell texts on scrolling 【发布时间】:2011-06-16 11:06:08 【问题描述】:

我在我的实现中使用了 Cell.ContentView 来自定义单元格内容。它工作正常,但唯一的问题是当我有很多单元格并且我上下滚动它们时,单元格内容被覆盖到单元格中,然后隐藏然后可见。假设我向上滚动第一个单元格然后再次将其向下滚动,最后一个单元格的内容会被第一个单元格覆盖!!

我对此进行了足够多的调试,但找不到确切的解决方案。我尝试检查 Cell.ContentView.SubViews 计数,如果它为 0,则仅添加其他子视图。在我上下滚动它们之前,这不会显示任何单元格内容,但是一旦出现内容,它就不会覆盖..有点奇怪..!!我还确保我正确地重复使用了单元格。以下是我将子视图添加到单元格内容视图中的代码。请告诉我如何才能摆脱这个问题。

P.S:不用担心我所做的变量和计算。假设它返回正确的值。 :)

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

    NSInteger totalAvailableSpace = IPHONE_DISPLAY_WIDTH - iconSize - accesorySize - 10;
    NSInteger lableHeight = [[cellDetails objectForKey:@"TableItemTextFontSize"] intValue] * 2 + 10;

    UILabel *textLabel = nil;
    textLabel = [[[UILabel alloc] initWithFrame:CGRectMake(iconSize+12, self.tableCellHeight/2 - lableHeight/2, totalAvailableSpace * 0.8, lableHeight)] autorelease];
    textLabel.numberOfLines = 2;
    textLabel.lineBreakMode = UILineBreakModeWordWrap;
    textLabel.textAlignment = UITextAlignmentLeft;
    textLabel.text = [cellDetails objectForKey:@"TableItemMainText"];
    if ([textLableColor scanHexInt:&hex]) 
        textLabel.textColor = UIColorFromRGB(hex);
    
    textLabel.font = [UIFont fontWithName:[cellDetails objectForKey:@"TableItemTextFontName"] size:[[cellDetails objectForKey:@"TableItemTextFontSize"] intValue]]; 
    [cell.contentView addSubview:textLabel];
    textLabel.backgroundColor = [UIColor clearColor];

    lableHeight = [[cellDetails objectForKey:@"TableItemDetailTextFontSize"] intValue] * 2 + 10;
    UILabel *detailTextLabel = nil;
    detailTextLabel = [[[UILabel alloc] initWithFrame:CGRectMake(iconSize+10+totalAvailableSpace * 0.8+5, self.tableCellHeight/2 - lableHeight/2, totalAvailableSpace * 0.2 - 10, lableHeight)] autorelease];
    detailTextLabel.numberOfLines = 2;
    detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
    detailTextLabel.textAlignment = UITextAlignmentLeft;
    detailTextLabel.text = [cellDetails objectForKey:@"TableItemDetailText"];
    if ([detailTextLableColor scanHexInt:&hex]) 
        detailTextLabel.textColor = UIColorFromRGB(hex);
    
    detailTextLabel.font = [UIFont fontWithName:[cellDetails objectForKey:@"TableItemDetailTextFontName"] size:[[cellDetails objectForKey:@"TableItemDetailTextFontSize"] intValue]];
    [cell.contentView addSubview:detailTextLabel];
    detailTextLabel.backgroundColor = [UIColor clearColor];

    return cell;

谢谢。

【问题讨论】:

基于this,删除 cell===nil 条件似乎可行,但不是理想的解决方案! 【参考方案1】:

那是因为玩具一遍又一遍地将视图添加到您的单元格中。

您应该只在创建单元格时添加它们,并在重复使用单元格时设置标签。

您可以为标签设置标签,以便之后设置文本。下面的代码可以解决问题

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

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) 
        if(style == UITableViewCellStyleValue1)
            cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        else
            cell = [[[UITableViewCell alloc] initWithStyle:style reuseIdentifier:CellIdentifier] autorelease];


        NSInteger totalAvailableSpace = IPHONE_DISPLAY_WIDTH - iconSize - accesorySize - 10;
        NSInteger lableHeight = [[cellDetails objectForKey:@"TableItemTextFontSize"] intValue] * 2 + 10;

        UILabel *textLabel = nil;
        textLabel.tag = 1;
        textLabel = [[[UILabel alloc] initWithFrame:CGRectMake(iconSize+12, self.tableCellHeight/2 - lableHeight/2, totalAvailableSpace * 0.8, lableHeight)] autorelease];
        textLabel.numberOfLines = 2;
        textLabel.lineBreakMode = UILineBreakModeWordWrap;
        textLabel.textAlignment = UITextAlignmentLeft;
        textLabel.text = [cellDetails objectForKey:@"TableItemMainText"];
        if ([textLableColor scanHexInt:&hex]) 
            textLabel.textColor = UIColorFromRGB(hex);
        
        textLabel.font = [UIFont fontWithName:[cellDetails objectForKey:@"TableItemTextFontName"] size:[[cellDetails objectForKey:@"TableItemTextFontSize"] intValue]]; 
        [cell.contentView addSubview:textLabel];
        textLabel.backgroundColor = [UIColor clearColor];

        lableHeight = [[cellDetails objectForKey:@"TableItemDetailTextFontSize"] intValue] * 2 + 10;
        UILabel *detailTextLabel = nil;
        detailTextLabel.tag = 2;
        detailTextLabel = [[[UILabel alloc] initWithFrame:CGRectMake(iconSize+10+totalAvailableSpace * 0.8+5, self.tableCellHeight/2 - lableHeight/2, totalAvailableSpace * 0.2 - 10, lableHeight)] autorelease];
        detailTextLabel.numberOfLines = 2;
        detailTextLabel.lineBreakMode = UILineBreakModeWordWrap;
        detailTextLabel.textAlignment = UITextAlignmentLeft;
        detailTextLabel.text = [cellDetails objectForKey:@"TableItemDetailText"];
        if ([detailTextLableColor scanHexInt:&hex]) 
            detailTextLabel.textColor = UIColorFromRGB(hex);
        
        detailTextLabel.font = [UIFont fontWithName:[cellDetails objectForKey:@"TableItemDetailTextFontName"] size:[[cellDetails objectForKey:@"TableItemDetailTextFontSize"] intValue]];
        [cell.contentView addSubview:detailTextLabel];
        detailTextLabel.backgroundColor = [UIColor clearColor];

     else 

        UILabel *textLabel = (UILabel *)[cell viewWithTag:1];
        textLabel.text = [cellDetails objectForKey:@"TableItemMainText"];

        UILabel *detailTextLabel = (UILabel *)[cell viewWithTag:2];
        detailTextLabel.text = [cellDetails objectForKey:@"TableItemDetailText"];

    

    return cell;

【讨论】:

嗯...这是很好的方法。非常感谢! 是的,这就是重用单元格对象的全部目的:) 您应该删除“else”,当它们刚刚创建时,您不会向标签添加任何文本。 对不起@pablasso,我没听懂……最后一个是在调用委托方法时更新单元格标签文本的那个,我可以重用一个单元格实例。你指的是这个吗? 是的,如果你只在单元格不为零时设置文本,那么第一次运行时你会得到一个空白单元格。无论是否重复使用单元格,您都希望每次都设置文本。【参考方案2】:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:nil];

if (cell == nil) 
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];

确保dequeueReusableCellWithIdentifierreuseIdentifier 应该是nil

现在它可以工作了!!

【讨论】:

这不是完全正确的方法。您没有使用可重复使用的单元格来创建表格。每次滚动时,您正在创建单元格。【参考方案3】:

将所有单元格 UI 内容放在 if(cell==nil)uilabel,uilabel or anythingUI related ...因为在创建 cel 时 ui 应该只调用一次

【讨论】:

【参考方案4】:

需要明确的是,您的问题是,当您将单元格滚动到视图中时,您经常会发现新单元格的文本被写在刚刚滚动到屏幕外的单元格的顶部?

问题是dequeueReusableCellWithIdentifier: 没有“清理”单元格(它调用prepareForReuse,仅此而已),所以你所有的旧子视图仍然存在。如果您要重用单元格,则不应每次都重新创建这些子视图。相反,只需调整您从dequeueReusableCellWithIdentifier: 返回的单元格上现有子视图的属性,并仅在新分配的单元格上创建新子视图。子类化 UITableViewCell 可以帮助解决这个问题,既可以提供属性/变量来保存对这些子视图的引用,又可以通过将子视图的创建和更新移动到适当的方法中来更好地组织代码。或者你可以通过将 nil 传递给重用标识符来不重用单元格。

在您向上和向下滚动之前它没有显示任何内容的最可能原因是,新创建的单元格可能具有框架提供的文本字段和图像视图,如果框架确定,它们可能会被删除你实际上并没有使用它们。

【讨论】:

【参考方案5】:

ios5 中,UILineBreakModeWordWrap 已弃用。你应该改用NSLineBreakByWordWrapping

这会将您的代码更改为类似于detailTextLabel.lineBreakMode = NSLineBreakByWordWrappingtextLabel.lineBreakMode = NSLineBreakByWordWrapping

【讨论】:

以上是关于iPhone:向 Cell ContentView 添加子视图会在滚动时覆盖单元格文本的主要内容,如果未能解决你的问题,请参考以下文章

uitableview - 自定义图像不断加载到 cell.contentView

[cell addSubview:button] 和 [cell.contentview addsubview:button] 有啥不同

删除 cell.contentview 上的所有子视图,标签除外

cell.contentView systemLayoutSizeFittingSize:不适用于动态高度tableview

在 contentView(cell.imageView) 后面隐藏 UITableView 分隔符?

Tableview [cell.contentview viewwithtag:] 返回 nil