iOS 8 具有可变高度的自调整单元格
Posted
技术标签:
【中文标题】iOS 8 具有可变高度的自调整单元格【英文标题】:iOS 8 self sizing cells with changing height 【发布时间】:2015-05-26 21:03:01 【问题描述】:我使用自定义 UITableViewCells 创建了一个 tableview
tableview.rowHeight = UITableViewAutomaticDimension;
为了测试创建了一个 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];
当我选择一行时,我喜欢更改所选单元格的高度。我这样做:
- (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 似乎无法真正确定单元格的合适大小。 (有时它太宽/太小)等等。
实现可以动态改变高度的自定尺寸单元格的正确方法是什么?
【问题讨论】:
您是否设置了estimatedRowHeight
属性?
我没有设置estimatedRowHeight :) 但只是测试过,它对高度限制冲突的问题没有任何影响。
【参考方案1】:
这里有两个问题:
1.自动布局消息:Unable to simultaneously satisfy constraints.
这是因为您更新了自定义视图的height
约束,但没有更新contentView
的height
约束。因为你还设置了自定义视图的bottom
约束到contentViewbottom
,所以系统不能同时满足这两个约束:自定义视图不能有100的高度,同时连接到contentView的底部,而contentView仍然有高度为 10。
解决这个问题很容易。您为 contentView 定义高度约束并将其设置为自定义视图的高度:
[self.contentView mas_makeConstraints:^(MASConstraintMaker *make)
make.height.equalTo(self.testView);
];
这解决了问题。
2。更新单元格的高度
更新单元格高度并不容易,因为单元格高度由UITableViewController
处理,而不是单元格本身。当然,您可以更改单元格的高度,但只要UITableViewController
没有为单元格提供足够的空间,您就不会看到新的单元格高度。您会看到现在较高的单元格将与下一个单元格重叠。
所以你需要一种方法来告诉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?()
【讨论】:
对我不起作用(reloadRowsAtIndexPaths 上可能会发生崩溃),并且将 testView 链接到 contentView 的约束也可能触发 Autolayout 冲突。以上是关于iOS 8 具有可变高度的自调整单元格的主要内容,如果未能解决你的问题,请参考以下文章
具有自动调整大小的单元格的自定义 UICollectionViewLayout 会因估计的项目高度较大而中断
使用 UITableView 的可变高度自定义单元格调用 reloadData 时保持 UITableView 的当前位置