如何在表视图中的UITableViewCells中使用“自动布局”,让每个单元格的内容和子视图确定行高度(自身/自动),同时保持平滑的滚动性能?
当前回答
如果单元格高度根据内容是动态的,则应精确计算出它,然后在渲染单元格之前返回高度值。一种简单的方法是在表视图单元格代码中定义计数方法,以便控制器在表单元格高度委托方法处调用。如果高度取决于表格或屏幕的宽度,请不要忘记计算实际单元格框架宽度(默认值为320)。也就是说,在表单元格高度委托方法中,首先使用cell.frame来校正单元格宽度,然后调用单元格中定义的计数高度方法来获得合适的值并返回它。
PS。可以在另一个方法中定义用于生成单元格对象的代码,以便调用不同的表视图单元格委托方法。
其他回答
@smileyborg提出的解决方案几乎是完美的。如果您有一个自定义单元格,并且需要一个或多个具有动态高度的UILabel,则systemLayoutSizeFittingSize方法与启用自动布局相结合将返回一个CGSizeZero,除非您将所有单元格约束从单元格移到其contentView(如@TomSwift在这里建议的那样,如何调整超视图的大小以适应具有自动布局的所有子视图?)。
为此,您需要在自定义UITableViewCell实现中插入以下代码(感谢@Adrian)。
- (void)awakeFromNib{
[super awakeFromNib];
for (NSLayoutConstraint *cellConstraint in self.constraints) {
[self removeConstraint:cellConstraint];
id firstItem = cellConstraint.firstItem == self ? self.contentView : cellConstraint.firstItem;
id seccondItem = cellConstraint.secondItem == self ? self.contentView : cellConstraint.secondItem;
NSLayoutConstraint *contentViewConstraint =
[NSLayoutConstraint constraintWithItem:firstItem
attribute:cellConstraint.firstAttribute
relatedBy:cellConstraint.relation
toItem:seccondItem
attribute:cellConstraint.secondAttribute
multiplier:cellConstraint.multiplier
constant:cellConstraint.constant];
[self.contentView addConstraint:contentViewConstraint];
}
}
将@smileyborg答案与此混合应该会奏效。
我刚刚遇到一个非常重要的问题,作为回答发布。
@smileyborg的回答基本正确。但是,如果自定义单元格类的layoutSubviews方法中有任何代码,例如设置preferredMaxLayoutWidth,则不会使用以下代码运行:
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
这让我困惑了一阵子。然后我意识到这是因为它们只触发contentView上的layoutSubview,而不是单元格本身。
我的工作代码如下:
TCAnswerDetailAppSummaryCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TCAnswerDetailAppSummaryCell"];
[cell configureWithThirdPartyObject:self.app];
[cell layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height;
注意,如果您正在创建一个新的单元格,我很确定您不需要调用setNeedsLayout,因为它应该已经设置好了。在保存对单元格的引用的情况下,您可能应该调用它。不管怎样,它都不会造成任何影响。
另一个提示是,如果您使用的是单元格子类,则需要设置preferredMaxLayoutWidth等属性。正如@smileyborg提到的,“您的表视图单元格的宽度尚未固定到表视图的宽度”。这是正确的,如果您在子类中而不是在视图控制器中进行工作,则会遇到麻烦。但是,此时可以使用表格宽度简单地设置单元格框架:
例如,在计算高度时:
self.summaryCell = [self.tableView dequeueReusableCellWithIdentifier:@"TCAnswerDetailDefaultSummaryCell"];
CGRect oldFrame = self.summaryCell.frame;
self.summaryCell.frame = CGRectMake(oldFrame.origin.x, oldFrame.origin.y, self.tableView.frame.size.width, oldFrame.size.height);
(我碰巧缓存了这个特定的单元以供重用,但这无关紧要)。
如果单元格高度根据内容是动态的,则应精确计算出它,然后在渲染单元格之前返回高度值。一种简单的方法是在表视图单元格代码中定义计数方法,以便控制器在表单元格高度委托方法处调用。如果高度取决于表格或屏幕的宽度,请不要忘记计算实际单元格框架宽度(默认值为320)。也就是说,在表单元格高度委托方法中,首先使用cell.frame来校正单元格宽度,然后调用单元格中定义的计数高度方法来获得合适的值并返回它。
PS。可以在另一个方法中定义用于生成单元格对象的代码,以便调用不同的表视图单元格委托方法。
关于@smileyborg接受的答案,我发现
[cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]
在某些约束不明确的情况下是不可靠的。最好使用下面UIView上的帮助器类别强制布局引擎计算一个方向上的高度:
-(CGFloat)systemLayoutHeightForWidth:(CGFloat)w{
[self setNeedsLayout];
[self layoutIfNeeded];
CGSize size = [self systemLayoutSizeFittingSize:CGSizeMake(w, 1) withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityFittingSizeLevel];
CGFloat h = size.height;
return h;
}
其中w:是表视图的宽度
(对于底部读取的Xcode 8.x/Xcode 9.x)
注意Xcode 7.x中的以下问题,这可能是混淆的根源:
Interface Builder无法正确处理自动调整单元格大小的设置。即使你的约束绝对有效,IB仍然会抱怨,并给你令人困惑的建议和错误。原因是IB不愿意根据您的约束条件改变行的高度(以便单元格适合您的内容)。相反,它会保持行的高度不变,并开始建议您更改约束,您应该忽略这些约束。
例如,假设您已经设置好了一切,没有警告,没有错误,一切正常。
现在,如果您更改字体大小(在本例中,我将描述标签的字体大小从17.0更改为18.0)。
由于字体大小增加,标签现在希望占据3行(之前它占据2行)。
如果Interface Builder按预期工作,它将调整单元格的高度以适应新的标签高度。然而,实际发生的情况是IB显示红色的自动布局错误图标,并建议您修改拥抱/压缩优先级。
您应该忽略这些警告。相反,您可以*手动更改行的高度(选择“单元格”>“大小检查器”>“行高度”)。
我一次单击一次(使用上/下步进器)改变这个高度,直到红色箭头错误消失!(实际上,您会收到黄色警告,此时只需继续并执行“更新帧”,一切都应该正常)。
*请注意,您实际上不必在Interface Builder中解决这些红色错误或黄色警告-在运行时,一切都会正常工作(即使IB显示错误/警告)。只需确保在运行时控制台日志中没有出现任何自动布局错误。事实上,尝试总是更新IB中的行高度是非常令人讨厌的,有时几乎不可能(因为分数值)。为了防止烦人的IB警告/错误,您可以选择所涉及的视图,并在Size Inspector中为属性Ambiguity选择Verify Position Only
Xcode 8.x/Xcode 9.x看起来(有时)做的事情与Xcode 7.x不同,但仍然不正确。例如,即使抗压优先级/拥抱优先级设置为必需(1000),Interface Builder也可能拉伸或剪裁标签以适合单元格(而不是调整单元格高度以适合标签周围)。在这种情况下,它甚至可能不会显示任何自动布局警告或错误。或者,有时它完全像上面描述的Xcode7.x那样。
推荐文章
- 如何删除默认的导航栏空间在SwiftUI导航视图
- 如何在iOS中使用Swift编程segue
- Swift -整数转换为小时/分钟/秒
- Swift:声明一个空字典
- 在成功提交我的应用程序后,“太多符号文件”
- 首先添加一个UIView,甚至是导航栏
- 我如何改变UIButton标题颜色?
- 在Swift中如何调用GCD主线程上的参数方法?
- NSLayoutConstraints是可动画的吗?
- iOS -构建失败,CocoaPods无法找到头文件
- CFNetwork SSLHandshake iOS 9失败
- 请求失败:不可接受的内容类型:文本/html使用AFNetworking 2.0
- 缺少推荐的图标文件-该包不包含iPhone / iPod Touch的应用程序图标,像素为“120x120”,png格式
- 以编程方式创建segue
- 如何使用Xcode创建。ipa文件?