我正在做一个类似于聊天的应用程序,其中tableView显示动态高度单元格。
单元格的视图和子视图以正确的方式受到约束
以便 AutoLayout 可以预测单元格的高度
(顶部,底部,前导,尾随)
但是仍然-如您在视频中看到的那样-滚动指示器栏显示计算出的高度不正确:
它会在出现新行时重新计算高度。
视频: https://youtu.be/5ydA5yV2O-Q
(第二次尝试向下滚动都可以)
代码:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
这是一个简单的问题。有人可以帮我吗?
添加了github:
答案 0 :(得分:3)
您需要将tableFooterView
设置为空。
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView()
// your staff
}
答案 1 :(得分:2)
问题出在您的estimatedHeightForRowAt
方法上。顾名思义,它为表格提供了估计的高度,因此它可以对可滚动内容有所了解,直到显示实际内容为止。值越精确,滚动和高度估算就越平滑。
您应该将此值设置为足够大,以便可以用最大的内容表示单元格的高度。您的情况下650可以正常工作。
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 650
}
使用这种方法的结果会更好。
此外,在您需要基于索引的变体之前,无需实现委托高度的方法。您只需设置表格视图属性即可。
tableView.estimatedRowHeight = 650.0
tableView.rowHeight = .automaticDimension
优化
我在您的演示项目中注意到了另一件事。您在if-else
中使用了过多的cellForRowAtIndexPath
,这使它变慢了一点。尽量减少这种情况。我对此做了一些改进,它提高了性能。
定义一个用于保存消息文本的数组。
var messages = ["Lorem ipsum,"many more",.....]
将您的cellForRowAt indexPath
替换为以下内容:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell : WorldMessageCell
cell = tableView.dequeueReusableCell(withIdentifier: "WorldMessageCell", for: indexPath) as! WorldMessageCell
if indexPath.row < 14 {
cell.messageLabel.text = messages[indexPath.row]
}
else if indexPath.row >= 14 && indexPath.row != 27 {
cell.messageLabel.text = messages[14]
}
else if indexPath.row == 27 {
cell.messageLabel.text = messages.last
}
return cell
}
答案 2 :(得分:2)
根据您对我的评论的回答,当您设置
estimatedHeightForRowAt和heightForRowAt具有相同的值 工作
我可以确认您是对的,并且存在AutoLayout无法计算estimatedHeightForRowAt
的正确值的问题。因此,基本上有两种可能要做的事情:
答案 3 :(得分:2)
但仍然-如您在视频中看到的-滚动指示器栏显示计算出的错误高度:
所以您想要的是精确的内容高度。
为此,您不能使用静态estimatedRowHeight
。
您应该像下面那样实现更正确的估算。
...
var sampleCell: WorldMessageCell?
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "WorldMessageCell", bundle: nil), forCellReuseIdentifier: "WorldMessageCell")
sampleCell = UINib(nibName: "WorldMessageCell", bundle: nil).instantiate(withOwner: WorldMessageCell.self, options: nil)[0] as? WorldMessageCell
}
...
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if let cell = sampleCell {
let text = self.textForRowAt(indexPath)
// note: this is because of "constrain to margins", which value is actually set after estimation. Do not use them to remove below
let margin = UIEdgeInsets(top: 8, left: 20, bottom: 8, right: 20)
// without "constrain to margins"
// let margin = cell.contentView.layoutMargins
let maxSize = CGSize(width: tableView.frame.size.width - margin.left - margin.right,
height: CGFloat.greatestFiniteMagnitude)
let attributes: [NSAttributedString.Key: Any]? = [NSAttributedString.Key.font: cell.messageLabel.font]
let size: CGRect = (text as NSString).boundingRect(with: maxSize,
options: [.usesLineFragmentOrigin], attributes: attributes, context: nil)
return size.height + margin.top + margin.bottom
}
return 100
}
这太精确了(实际上是真实的行高),也许还很慢,但是您可以为优化进行更多近似估算。
答案 4 :(得分:2)
答案 5 :(得分:2)
使用粗略的单元格高度估计(或完全不提供它们,就像您所做的那样)时,这是预期的行为。仅当单元格出现在屏幕上时才计算实际高度,因此此时会调整滚动条的行程。如果使用它们,也希望有快速的插入/删除动画。
答案 6 :(得分:0)
为什么要在表视图中添加视图,没有它也可以工作。我只是删除了该视图并更改了一些约束(例如底部约束将安全区域更改为超级视图),所以效果很好。
download storyboard and add it to your project and then check
答案 7 :(得分:0)
在viewDidLoad()
tableView.estimatedRowHeight = 100.0
tableView.rowHeight = UITableView.automaticDimension
tableView.tableFooterView = UIView()
您应该删除两个高度数据源方法。
答案 8 :(得分:0)
您想做的是eliminate the extra blank cells。您可以通过在tableFooterView
方法中将UIView
设置为空的viewDidLoad
来实现。我从您的GitHub克隆了代码并修改了方法:
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "WorldMessageCell", bundle: nil), forCellReuseIdentifier: "WorldMessageCell")
tableView.tableFooterView = UIView()
}
将tableFooterView
设置为nil
也对我有用
tableView.tableFooterView = nil
答案 9 :(得分:0)
希望您能听到很多。因此请稍事休息,然后再回到办公桌上,并执行2-3步。
1)确保“单元格标签的自动版式”设置正确,如下所示。
2)UILabel的行数为文本的动态高度设置为零。
3)设置单元格的自动尺寸高度。
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
,我相信它应该起作用。查看我的代码结果。