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
约束,但没有更新 contentView
的 height
约束。因为你也设置了自定义视图的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?()
}
我使用
创建了一个带有自动调整 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
约束,但没有更新 contentView
的 height
约束。因为你也设置了自定义视图的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?()
}