在基于视图的NSTableView的,所述的NSTextField由NSImageView
TL限幅; DR:在基于视图的NSTableView的,所述的NSTextField由NSImageView
在MACOS 10.11,含有的NSTextField和NSImageView右文本字段下的图基于NSTableView的,与具有图像的某些行而其他则不然,有些文本在将表格向下滚动之后会被剪切掉。
之前滚动:
滚动后:
当我说 “裁剪” 这意味着该文本视图是在它的最小高度与自动布局定义,当它应该扩大,而不是。
请注意,这种错误行为只发生在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的仍然是阻止文本在某些情况下查看。
反正有时文本在第一显示裁剪,任何滚动完成之前...
CoreAnimation层
我想也许是细胞所需要的支持,使他们成为层正确地重新显示,所以我已经在scrollView,tableView,tableCell等上启用了CoreAnimation图层。但是我几乎没有看到任何区别。
A/B测试
如果我完全删除ImageView的,只处理文本框的一切工作正常。拥有imageView肯定是造成问题的原因。
自动布局
我试图处理的行内容的显示,而无需使用自动布局,但无济于事。我也尝试设置不同的约束条件,但很显然,我吮吸自动布局,并没有设法找到一个好的替代方案来解决我目前的限制。
替代方案:用NSAttributedString图像
我试图去除图像视图,且具有图像添加在文本视图,而不是归因字符串的结尾。但是结果通常很糟糕,而且在大多数情况下它不起作用(例如,无法及时下载图像以将其添加到属性字符串中,使单元格根本没有文本或图像并在错误的高度)。
问题
我在做什么错?我怎样才能解决这些问题?我的猜测是我应该改变自动布局约束,但我没有看到一个可行的解决方案。
或者你可能会完全不同吗?
文本字段在IB中具有“首选宽度”字段,允许调整固有大小与自动布局计算大小的关联。
将此IB属性值更改为“First Runtime Layout Width”或“Explicit”通常有助于解决类似问题。
这解决了过去我的很多问题。
这解决了小牛的问题,似乎并没有改变塞拉利昂的任何事情。非常感谢,尤金! :) – Moritz
你在说'NSTextView'和你正在使用'NSTextField'的图片和代码。你有没有检查'nosbounds.size'在'heightOfRow'中是否正确? – Willeke
Arf,我的错,我在测试的时候从NSTextView变成了NSTextField,并且忘记恢复原状了。你认为使用NSTextField是错误的,我应该回到NSTextView? // Woah,ns.bounds.size总是具有零高度......不知道发生了什么,是因为NSTextField而不是NSTextView? – Moritz
我刚刚发现,这在macOS 10.12 Sierra中没有问题。错误的行为只发生在macOS 10.11 Mavericks ... oO – Moritz