动态高度可重复使用UITableViewCell

时间:2013-11-28 02:13:53

标签: ios objective-c uitableview

这个问题在SO上被问了100次,但我无法解决我的问题。

我有两个可自定义的单元格。两者都有动态高度。我的tableView:heightForRowAtIndexPath:返回每个单元格的正确高度,但是当重复使用单元格时,单元格之间的分隔线在100%的时间内不在正确的位置。我无法使用在我的单元格中添加自己的行的黑客攻击,因为有时重叠非常糟糕,您无法单击右侧单元格。

我需要做些什么来确保它使用正确的高度?

以下是分隔线位于错误位置(假设位于标题正上方)的示例:

screenshot http://f.cl.ly/items/2z1e3s0N1g213R414129/Screenshot_2013.11.27_17.49.45.png

以下是我设定的高度:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    InspectionItem *item = [items objectAtIndex:indexPath.row];
    int t = [item.rating.ratingType ratingTypeK];

    if (t == RatingTypeTextfield){
        CGFloat height = [OQCTextFieldCell heightOfCellWithTitle:item.name
                                                         subtext:item.descriptionText
                                                            text:item.comment
                                                  andScreenWidth:self.view.frame.size.width];
        return height;
    }
    else {
        CGFloat height = [OQCButtonCell heightOfCellWithTitle:item.name
                                                      subtext:item.descriptionText
                                               andScreenWidth:self.view.frame.size.width];
        return height;
    }
}

同样,这些类方法返回正确的高度。

以下是我设置单元格的方法(简短版本):

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    InspectionItem *item = [items objectAtIndex:indexPath.row];
    int t = [item.rating.ratingType ratingTypeK];

    if (t == RatingTypeTextfield){
        static NSString *CellIdentifier = @"TextFieldCell";
        OQCTextFieldCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

        cell.titleLabel.text = item.name;
        ...
        return cell;
    }
    else {
        static NSString *CellIdentifier = @"ButtonCell";
        OQCButtonCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

        cell.titleLabel.text = item.name;
        ...
        return cell;
    }
}

以下是我如何注册我的单元格:

UINib *buttonNib = [UINib nibWithNibName:@"OQCButtonCell" bundle:[NSBundle mainBundle]];
[self.tableView registerNib:buttonNib forCellReuseIdentifier:@"ButtonCell"];

UINib *textFieldNib = [UINib nibWithNibName:@"OQCTextFieldCell" bundle:[NSBundle mainBundle]];
[self.tableView registerNib:textFieldNib forCellReuseIdentifier:@"TextFieldCell"];

UINib *flagNib = [UINib nibWithNibName:@"OQCFlagCell" bundle:[NSBundle mainBundle]];
[self.tableView registerNib:flagNib forCellReuseIdentifier:@"FlagCell"];

我的细胞只覆盖layoutSubviews,他们确实称之为超级优先。

我需要解决方案才能适用于iOS 5.2 +。

更新

以下是layoutSubviews的代码。我相信我的自定义方法heightOfCellWithTitle:subtext:text:会返回正确的高度,因为它与此方法末尾的layoutSubview height变量相匹配。

- (void)layoutSubviews
{
    [super layoutSubviews];

    CGFloat height = 0;

    // Title + Header background view
    NSString *title = titleLabel.text;
    CGRect frame = self.titleLabel.frame;
    CGSize size = [title sizeWithFont:titleLabel.font
                    constrainedToSize:CGSizeMake(frame.size.width, 9999)
                        lineBreakMode:titleLabel.lineBreakMode];
    size.width = frame.size.width; // don't let it shrink
    titleLabel.numberOfLines = size.height / titleLabel.font.lineHeight;
    frame.size = size;
    self.titleLabel.frame = frame;

    frame = self.headerBackgroundView.frame;
    frame.size.height = size.height + 8;
    self.headerBackgroundView.frame = frame;

    // single line of text should be 30
    height += frame.size.height;

    CGRect subContentFrame = subContentView.frame;
    subContentFrame.origin.y = height;

    CGFloat subHeight = 0;

    // Label
    title = subtextLabel.text;
    if ([title length] > 0){
        subHeight += 5; // top margin
        size = [title sizeWithFont:subtextLabel.font
                 constrainedToSize:CGSizeMake(subtextLabel.frame.size.width, 9999) lineBreakMode:subtextLabel.lineBreakMode];
        size.width = self.contentView.frame.size.width - 52; // don't let it shrink
        subtextLabel.numberOfLines = size.height / subtextLabel.font.lineHeight;
        frame = self.subtextLabel.frame;
        frame.size = size;
        frame.origin.y = subHeight;
        self.subtextLabel.frame = frame;
        // subtext height + bottom margin
        subHeight += size.height + 5;
    }
    else {
        subHeight += 25;
    }
    // Button
    frame = button.frame;
    frame.origin.y = subHeight;
    button.frame = frame;

    subHeight += frame.size.height + 25;

    subContentFrame.size.height = subHeight;
    subContentView.frame = subContentFrame;

    // reposition detailIndicator
    frame = self.detailIndicator.frame;
    frame.origin.x = subContentView.frame.size.width - 37;
    self.detailIndicator.frame = frame;

    height += subHeight;

    // Drawer
    frame = CGRectMake(0, 0, self.frame.size.width, height);

    [self.drawerView setFrame:frame];

    self.backgroundView = self.drawerView;
}

另外,快速记下我一直在检查的数字。

我有一个layoutSubviewstableView:heightForRowAtIndexPath:登录,它给了我正确的高度(我基于layoutSubviews,因为它重新计算整个单元格的高度)。然后我有tableView:cellForRowAtIndexPath:的日志,在我返回单元格的最后,我打印出单元格的高度,这是一个重用视图的旧高度,我有点期待。我将假设在返回单元格后,iOS将根据tableView:heightForRowAtIndexPath:重新计算单元格的位置,并使用layoutSubviews重新定位视图。

2 个答案:

答案 0 :(得分:0)

所以如果你在单元格类中动态布局单元格并覆盖layoutSubviews,这在heightForRowAtIndexPath中应该足够了:

UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
float height = cell.frame.size.height;
return height;

请记住,您必须将单元格中的所有uiviews“重置”为起始值。否则,单元格将使用当前值,即如果您在y = 10处有标签并将其以编程方式设置为y = 20,则下次使用该单元格时,单元格仍具有y = 20。

答案 1 :(得分:0)

您是否尝试过调用

[cell setNeedsLayout];
[cell layoutIfNeeded];

返回之前?