TL; DR:
在macOS 10.11中,基于视图的NSTableView在文本字段下方包含NSTextField和NSImageView,其中一些行具有图像而其他行没有,有些文本在向下滚动表格之后被剪切。
滚动前:
滚动后:
当我说"剪辑"这意味着文本视图处于自动布局定义的最小高度,而应该扩展它。
请注意,此错误行为仅发生在macOS 10.11 Mavericks中。 macOS 10.12 Sierra没有这样的问题。
macOS 10.11 +,基于视图 NSTableView。
每行都有一个文本字段,以及文本字段正下方的图像视图。
所有元素都具有在IB中设置的自动布局约束。
文本视图必须垂直调整其高度 - 图像视图应相应移动,保持粘在文本字段的底部。
当然行本身也必须适应它的高度。
有时候没有要显示的图像,在这种情况下,图像视图不应该是可见的。
这是它在正常工作时应该呈现的方式:
该行是NSTableCellView的子类。
在单元格中,文本字段设置为属性字符串。
在tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat
中,我创建了一个虚拟textView,用于查找实际文本字段的高度,并相应地返回修改后的行高。我还检查是否有要显示的图像,如果是这样的话我将图像高度添加到行高。
let ns = NSTextField(frame: NSRect(x: 0, y: 0, width: defaultWidth, height: 0))
ns.attributedStringValue = // the attributed string
var h = ns.attributedStringValue.boundingRect(with: ns.bounds.size, options: [.usesLineFragmentOrigin, .usesFontLeading]).height
if post.hasImage {
h += image.height
}
return h + margins
在tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?
中,我准备了实际的细胞内容:
getUserAvatar { img in
DispatchQueue.main.async {
cell.iconBackground.layer?.backgroundColor = self.prefs.colors.iconBackground.cgColor
cell.iconBackground.rounded(amount: 6)
cell.iconView.rounded(amount: 6)
cell.iconView.image = img
}
}
cell.usernameLabel.attributedStringValue = xxx
cell.dateLabel.attributedStringValue = xxx
// the textView at the top of the cell
cell.textLabel.attributedStringValue = xxx
// the imageView right under the textView
if post.hasImage {
getImage { img in
DispatchQueue.main.async {
cell.postImage.image = img
}
}
}
滚动tableView时,只要一行或多行在图像视图中显示图像,就会出现问题。
有时文字被剪裁,可能是因为空图像视图掩盖了文本的底部:
正常的
削波
重要提示:调整表格大小会触发重绘并修复显示问题......
我认为主要问题是因为tableView重用了单元格。
所以我默认隐藏了tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?
中的图片字段,只有在设置图像时才取消隐藏,我在主线程上执行此操作:
guard let cell = tableView.make(withIdentifier: "xxx", owner: self) as? PostTableCellView else {
return nil
}
DispatchQueue.main.async {
cell.postImage.isHidden = true
cell.postImage.image = nil
}
// set the text view here, the buttons, labels, etc, then this async part runs:
downloadImage { img in
DispatchQueue.main.async {
cell.postImage.isHidden = false
cell.postImage.image = img
}
}
// more setup
return cell
但在某些情况下,imageView仍然会阻止文本视图。
无论如何,有时在完成任何滚动之前,文本会在第一个显示处被剪切......
我想也许这些单元格需要进行图层备份才能正确地重新显示,所以我在scrollView,tableView,tableCell等上启用了CoreAnimation图层。但我几乎看不出任何区别
如果我完全删除imageView并且只处理文本字段,一切正常。拥有imageView绝对是导致问题的原因。
我试图在不使用自动布局的情况下处理行内容的显示,但无济于事。我也试图设置不同的约束条件,但显然我对autolayout感到厌烦,并没有设法找到一个替代当前约束的好方法。
我尝试删除图片视图,并在文本视图中的属性字符串末尾添加图片。但结果往往是丑陋的 - 当它工作时 - 并且大多数时候它只是不起作用(例如,当图像无法及时下载以添加到属性字符串时,使单元格没有文本或图像完全和错误的高度。)
我做错了什么?我该如何解决这些问题?我的猜测是我应该更改自动布局限制,但我没有看到有效的解决方案。
或许你会以完全不同的方式做到这一点?