高度不同的分组UITableView行会导致内容混乱

高度不同的分组UITableView行会导致内容混乱,uitableview,Uitableview,我尽了最大努力先在这里找到答案,但我被卡住了。我有一个UITableView集合,其中UITableViewStyle由4个部分组成,每个部分有一行或两行。在其中的两个部分中,我需要一个更高的行来容纳我粘贴的内容 看起来不错,但当我上下滚动时,文本标签、附件和额外的子视图开始转移到不同的行中,我不知道为什么 这显示了加载时的表视图,然后在我上下滚动几次之后。每次我滚动不同的行内容时都会出现混乱 我想我读到一些关于这是一个分组风格的问题。果不其然,如果我将表格样式更改为默认样式,我不会看到这个问题

我尽了最大努力先在这里找到答案,但我被卡住了。我有一个UITableView集合,其中UITableViewStyle由4个部分组成,每个部分有一行或两行。在其中的两个部分中,我需要一个更高的行来容纳我粘贴的内容

看起来不错,但当我上下滚动时,文本标签、附件和额外的子视图开始转移到不同的行中,我不知道为什么

这显示了加载时的表视图,然后在我上下滚动几次之后。每次我滚动不同的行内容时都会出现混乱

我想我读到一些关于这是一个分组风格的问题。果不其然,如果我将表格样式更改为默认样式,我不会看到这个问题。使用分组样式时,是否不允许动态设置某些行的高度

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
     if (indexPath.section == kSection_Info && indexPath.row == kSectionRow_InfoPhoto)
     {
      return 84.0;
     }
     else if (indexPath.section == kSection_Level && indexPath.row == kSectionRow_LevelLevel)
     {
      return 70.0;
     }
     return 44.0;
}
我正在celForRowAtIndexPath中手动设置每一行:

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

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

        switch (indexPath.section)
        {
            case kSection_Info:
            {
                switch (indexPath.row)
                {
                    case kSectionRow_InfoName:
                    {
                        cell.textLabel.text = @"Name";
                        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
                        self.nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(74, 8, 195, 25)];
                        self.nameLabel.textAlignment = UITextAlignmentRight;
                        self.nameLabel.font = [UIFont systemFontOfSize:16];
                        self.nameLabel.textColor = [UIColor blueColor];
                        self.nameLabel.text = self.currentRecipient.fullName;                       
                        [cell.contentView addSubview:self.nameLabel];

                        break;
                    }
                    case kSectionRow_InfoPhoto:
                    {
                        cell.textLabel.text = @"Photo";
                        self.imageButton = [UIButton buttonWithType:UIButtonTypeCustom];
                        self.imageButton.frame = CGRectMake(10, 14, 64, 64);
                        [self.imageButton addTarget:self action:@selector(onImageButtonTouch:) forControlEvents:UIControlEventTouchUpInside];                   

                        NSString *imageName = @"add_image.png";
                        UIImage *thumb = [UIImage imageNamed:imageName];
                        [self.imageButton setImage:thumb forState:UIControlStateNormal];
                        cell.accessoryView = self.imageButton;

                        break;
                    }
                    default:
                    {
                        break;
                    }
                }
                break;
            }

            case kSection_List:
            {
                switch (indexPath.row)
                {
                    case kSectionRow_ListHasList:
                    {
                        cell.textLabel.text = @"Is Listed";                 
                        self.listSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
                        cell.accessoryView = self.listSwitch;                   

                        break;
                    }
                    case kSectionRow_ListBudget:
                    {
                        cell.textLabel.text = @"List Amount";
                        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
                        self.budgetLabel = [[UILabel alloc] initWithFrame:CGRectMake(124, 8, 145, 25)];
                        self.budgetLabel.textAlignment = UITextAlignmentRight;
                        self.budgetLabel.font = [UIFont systemFontOfSize:16];
                        self.budgetLabel.textColor = [UIColor blueColor];
                        self.budgetLabel.text = [@"$" stringByAppendingFormat:@"%0.2f", [self.currentRecipient.budget floatValue]];                     
                        [cell.contentView addSubview:self.budgetLabel];

                        break;
                    }
                    default:
                    {
                        break;
                    }
                }
                break;
            }   

            case kSection_Level:
            {
                switch (indexPath.row)
                {               
                    case kSectionRow_LevelLevel:
                    {
                        self.levelSlider = [[UISlider alloc] initWithFrame:CGRectMake(8, 2, 284, 40)];
                        self.levelSlider.minimumValue = 0.0;
                        self.levelSlider.maximumValue = 100.0;
                        self.levelSlider.continuous = YES;

                        UIImage *meterImage = [UIImage imageNamed:@"meter_labels.png"];
                        UIImageView *meterView = [[UIImageView alloc] initWithFrame:CGRectMake(8, 32, 284, 24)];
                        [meterView setImage:meterImage];

                        [cell.contentView addSubview:self.levelSlider];
                        [cell.contentView addSubview:meterView];
                        [meterImage release];

                        break;
                    }
                    case kSectionRow_LevelHasLevel:
                    {
                        cell.textLabel.text = @"Show Level";
                        self.levelSwitch = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
                        cell.accessoryView = self.levelSwitch;                              
                        break;
                    }                       
                    default:
                    {
                        break;
                    }
                }
                break;
            }

            case kSection_RecipientDelete:
            {
                cell.textLabel.text = @"Delete Recipient";          
                cell.textLabel.textAlignment = UITextAlignmentCenter;
                cell.textLabel.textColor = [UIColor blueColor];             
                break;
            }

            default:
            {
                break;
            }
        }
    }

    return cell;
}
您看到的“内容混乱”很可能是由于对单元格重复使用的不当处理

分组样式没有特别的问题。问题更可能以这种方式表现出来,因为屏幕中容纳的单元格更少,需要更多的滚动,需要更多的单元格重复使用

您仅在创建单元格时设置单元格内容(当单元格==nil时)。当一个单元格从屏幕上滚下时,它进入重用队列。现在可见的另一端的行重新使用重复使用队列中的单元格视图。重复使用的单元格包含其他行的内容

当所有单元格都相似时(至少在UI控件而不是数据方面),这不是问题。当所有或部分单元格都不同时,您会看到控件出现在您不希望它们出现的位置


因为您只有少量的行,并且每个行的布局都不同,所以快速(可能是脏的)解决方案是为每个单元格使用不同的重用标识符,如下所示:

NSString *CellIdentifier = 
    [NSString stringWithFormat:@"RecipientEntryCell-%d-%d", 
     indexPath.section, indexPath.row];
static NSString *CellIdentifier = @"CellIdentifier";

UITableViewCell *cell = [tableView dequeueReusableCell...
if (cell == nil) {
    //Create cell...
    //Set UI content that applies to all rows (if any)...
}
else {
    //Cell is being re-used.
    //Remove UI content that doesn't apply to this row...
}

//Add UI content that applies only to this row...

//Copy values from data source to cell UI controls...

return cell;
如果表视图将有许多不同的单元格,则不建议这样做,因为表中每行的每个单元格都将同时在内存中(而不仅仅是屏幕上的少数单元格)不要使用唯一标识符来解决任何和所有单元格重复使用问题。

《表视图编程指南》显示了一种类似于这样设计表视图的替代方法,其中有几个单元格具有不同的布局。请参阅上的“静态行内容的技术”


最终,如果您了解表视图有充分的理由重复使用单元格,而不是一直试图绕过它,那就更好了。通常,CellForRowatineXpath应如下所示:

NSString *CellIdentifier = 
    [NSString stringWithFormat:@"RecipientEntryCell-%d-%d", 
     indexPath.section, indexPath.row];
static NSString *CellIdentifier = @"CellIdentifier";

UITableViewCell *cell = [tableView dequeueReusableCell...
if (cell == nil) {
    //Create cell...
    //Set UI content that applies to all rows (if any)...
}
else {
    //Cell is being re-used.
    //Remove UI content that doesn't apply to this row...
}

//Add UI content that applies only to this row...

//Copy values from data source to cell UI controls...

return cell;
如果如上所示构造单元格,请不要在单元格内维护对UI控件(如nameLabel、imageButton等)的类级引用。相反,应在cellForRowAtIndexPath中从备份数据变量(模型)中设置控件值,并应在UI控件更改后立即将该值读取或保存回备份数据变量

例如,与其在单元格中存储对UISlider的引用,不如将当前滑块值存储为float ivar。在适当的地方初始化浮动(例如viewDidLoad)。在cellForRowAtIndexPath中,创建UISlider,使用float ivar设置其值,并让滑块在其值更改时调用方法。在该方法中,将滑块的值复制到float ivar


希望这有帮助。

您的
tableView:cellforrowatinexpath:
方法是什么样子的?将其添加到我的问题中,谢谢!非常感谢您的详细回复。我在试着调试时做了一些测试,并且意识到了同样的事情。我当前的问题与表格样式或行高无关。这一切都与我不知道用不同的静态内容构建表的正确方法有关。我真的只想要用于布局和样式的表,所以我不介意在IB中构建唯一的单元格。我也会接受您关于避免类级引用的建议