如何在表视图中的UITableViewCells中使用“自动布局”,让每个单元格的内容和子视图确定行高度(自身/自动),同时保持平滑的滚动性能?
当前回答
swift 4
@IBOutlet weak var tableViewHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var tableView: UITableView!
private var context = 1
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.addObserver(self, forKeyPath: "contentSize", options: [.new,.prior], context: &context)
}
// Added observer to adjust tableview height based on the content
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &self.context{
if let size = change?[NSKeyValueChangeKey.newKey] as? CGSize{
print("-----")
print(size.height)
tableViewHeightConstraint.constant = size.height + 50
}
}
}
//Remove observer
deinit {
NotificationCenter.default.removeObserver(self)
}
其他回答
以下是我的解决方案:
在TableView加载视图之前,您需要告诉它估计的高度。否则它将无法像预期的那样运行。
目标-C
- (void)viewWillAppear:(BOOL)animated {
_messageField.delegate = self;
_tableView.estimatedRowHeight = 65.0;
_tableView.rowHeight = UITableViewAutomaticDimension;
}
更新至Swift 4.2
override func viewWillAppear(_ animated: Bool) {
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 65.0
}
在我的例子中,填充是因为sectionHeader和sectionFooter的高度,故事板允许我将其更改为最小值1。因此,在viewDidLoad方法中:
tableView.sectionHeaderHeight = 0
tableView.sectionFooterHeight = 0
我刚刚遇到一个非常重要的问题,作为回答发布。
@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);
(我碰巧缓存了这个特定的单元以供重用,但这无关紧要)。
我只是对rowHeight和estimatedRowHeight的两个值进行了一些愚蠢的尝试和错误,并认为它可能会提供一些调试细节:
如果同时设置它们,或者仅设置估计的RowHeight,则将获得所需的行为:
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 1.00001 // MUST be greater than 1
建议您尽最大努力得到正确的估计,但最终结果并无不同。这只会影响你的表现。
如果只设置rowHeight,即只执行以下操作:
tableView.rowHeight = UITableViewAutomaticDimension
您的最终结果不会如预期:
如果将estimatedRowHeight设置为1或更小,则无论rowHeight如何,都会崩溃。
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 1
我崩溃了,出现以下错误消息:
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'table view row height
must not be negative - provided height for index path (<NSIndexPath:
0xc000000000000016> {length = 2, path = 0 - 0}) is -1.000000'
...some other lines...
libc++abi.dylib: terminating with uncaught exception of type
NSException
假设您有一个带有子视图的单元格,并且希望该单元格的高度足够高,以包含子视图+填充。
1) 将子视图的底部约束设置为cell.contentView减去所需的填充。不要对单元格或cell.contentView本身设置约束。
2) 将tableView的rowHeight属性或tableView:heightForRowAtIndexPath:设置为UITableViewAutomaticDimension。
3) 将tableView的estimatedRowHeight属性或tableView:estimatedHeightForRowAtIndexPath:设置为高度的最佳猜测。
就是这样。
推荐文章
- 如何更改导航栏上“后退”按钮的标题
- 我如何获得iOS 7默认的蓝色编程?
- UITapGestureRecognizer破坏UITableView didSelectRowAtIndexPath
- 在Objective-C中@property保留,赋值,复制,非原子
- 6.5英寸屏幕的App store截图大小是多少?
- 我如何在NSAttributedString中创建一个可点击的链接?
- iOS测试/规格TDD/BDD以及集成和验收测试
- 停止UIWebView垂直“弹跳”?
- 启动屏幕故事板不显示图像
- 是否可以为iPhone应用程序(如YouTube和地图)注册一个基于http+域的URL方案?
- 模拟器错误fbssystemservicdomain代码4
- 改变UISegmentedControl的字体大小
- 我可以强制UITableView隐藏分隔符之间的空单元格吗?
- 获取用户当前位置/坐标
- 获得推送通知,而应用程序在前台iOS