iOS 8 个高度可变的自调整单元格

iOS 8 self sizing cells with changing height

我使用

创建了一个带有自动调整 UITableViewCells 的表格视图

tableview.rowHeight = UITableViewAutomaticDimension;

为了测试,a 创建了一个 UIView 并将其添加到 cell.contentView 并具有以下限制。 (使用砌体)

- (void)updateConstraints {
    UIView *superview = self.contentView;

    if (!_didSetupConstraints) {
        [self.testView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.equalTo(superview);
            make.height.equalTo(@10.0f);
            make.left.equalTo(superview);
            make.right.equalTo(superview);
            make.bottom.equalTo(superview);
        }];

        _didSetupConstraints = YES;
    }

    [super updateConstraints];
}

当我 select 行时,我想更改 selected 单元格的高度。我这样做:

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    [self.testView mas_updateConstraints:^(MASConstraintMaker *make) {
        if (selected) {
            make.height.equalTo(@100);
        }
        else {
            make.height.equalTo(@10);
        }
    }];

    [UIView animateWithDuration:0.3f animations:^{
        [super layoutIfNeeded];
    }];
}

它似乎有效,但是,xcode 抱怨以下错误:

Unable to simultaneously satisfy constraints.

那么问题是 contentView 正在自行创建高度限制(因为默认情况下 contentView.translatesAutoresizingMaskIntoConstraints = YES;)。

所以当updateConstraints是第一个运行时,系统会在contentView上创建一个等于10.0f

的高度约束

之后,当调用 setSelected... 时,我改变了 testView 的高度,因此 testView.height (100.0f) 和 contentView.height (10.0f) 之间存在冲突,并且因为 testView 附在 contentView 的底部(为了让自调整大小的单元格工作)它给出了错误。

我尝试设置 contentView.translatesAutoresizingMaskIntoConstraints = NO;,但 UITableViewCell 似乎无法确定单元格的合适大小。 (有时它太宽/太小)等等

实现可以动态改变高度的自调整单元格的正确方法是什么?

这里有两个问题:

1.自动布局消息:Unable to simultaneously satisfy constraints.

这是因为您更新了自定义视图的 height 约束,但没有更新 contentViewheight 约束。因为你也设置了自定义视图的bottom约束到contentViewbottom,系统不能满足这两个约束:自定义视图不能有100的高度,同时连接到contentView的底部,而contentView 的高度仍然是 10。

解决这个问题很容易。您为 contentView 定义高度约束并将其设置为自定义视图的高度:

[self.contentView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.height.equalTo(self.testView);
}];

这解决了问题。

2。更新单元格的高度

更新单元格高度并不容易,因为单元格高度是由 UITableViewController 而不是单元格本身处理的。当然你可以改变单元格的高度,但是只要 UITableViewController 没有给单元格足够的 space 你就不会看到新的单元格高度。您会看到现在更高的单元格将与下一个单元格重叠。

所以您需要一种方法来告诉 UITableViewController 它应该更新单元格的高度。您可以通过调用 reloadRowsAtIndexPaths:withRowAnimation: 来做到这一点。这会重新加载单元格并很好地对其进行动画处理。因此,单元格必须以某种方式在 UITableViewController 上调用该方法。那里的挑战:UITableViewCell 没有引用它的 UITableViewController(它不应该)。

你可以做的是子类化 UITableViewCell 并给它一个闭包 属性 只要它的高度发生变化它就可以执行:

class DynamicHeightTableViewCell: UITableViewCell {
    var heightDidChange: (() -> Void)?
    ...

现在,当您将 UITableViewControllerDataSource 中的一个单元格出队时,您可以设置它的关闭:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier("DynamicHeightTableViewCell", forIndexPath: indexPath)
    if let customCell = cell as? DynamicHeightTableViewCell {
        customCell.heightDidChange = { [weak cell, weak tableView] in
            if let currentIndexPath = tableView?.indexPathForCell(cell!) {
                tableView?.reloadRowsAtIndexPaths([currentIndexPath], withRowAnimation: .Automatic)
            }
        }
    }

    return cell
}

然后,当单元格改变其高度时,您只需执行闭包,单元格就会重新加载:

func theFunctionWhereTheHeightChanges() {

   // change the height

   heightDidChange?()
}