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

时间:2010-11-28 20:32:43

标签: uitableview

我最难在这里找到答案,但我被困住了。我有一个UITableView设置与UITableViewStyleGrouped有4个部分,每个部分有一行或两行。在其中两个部分中,我需要一个更大的高度来容纳我坚持的内容。

看起来不错,除非我向上和向下滚动,textLablels,配件和额外的子视图开始转移到不同的行,我无法弄清楚原因。

screenshot在加载时显示表格视图,然后在我向上和向下滚动几次后显示。每次我滚动不同的行内容shuffles。

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

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

1 个答案:

答案 0 :(得分:0)

您看到的“内容改组”很可能是由于对细胞重复使用的处理不当造成的。

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

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

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


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

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

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

“表视图编程指南”显示了另一种设计表视图的方法,其中有几个具有不同布局的单元格。请参阅this page上的“静态行内容技术”。


最终,如果您了解表视图出于好的原因重新使用单元格而不是一直尝试解决它,那就更好了。通常,cellForRowAtIndexPath应如下所示:

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。在适当的位置初始化float(例如viewDidLoad)。在cellForRowAtIndexPath中,创建UISlider,使用float ivar设置其值,并在其值更改时让滑块调用方法。在该方法中,将滑块的值复制到float ivar。

希望这有帮助。