在基于视图的NSTableView的,所述的NSTextField由NSImageView

问题描述:

TL限幅; DR:在基于视图的NSTableView的,所述的NSTextField由NSImageView

在MACOS 10.11,含有的NSTextField和NSImageView右文本字段下的图基于NSTableView的,与具有图像的某些行而其他则不然,有些文本在将表格向下滚动之后会被剪切掉。

之前滚动:

enter image description here

滚动后:

enter image description here

当我说 “裁剪” 这意味着该文本视图是在它的最小高度与自动布局定义,当它应该扩大,而不是。

请注意,这种错误行为只发生在macOS 10.11 Mavericks中。 macOS 10.12 Sierra没有这样的问题。


语境

MACOS 10.11+,视图基于 NSTableView的。

每行都有一个文本框和一个位于文本框下方的图像视图。

所有元素都在IB中设置了自动布局约束。

enter image description here

enter image description here

目标

文本视图具有垂直调整其高度 - 图像视图应该相应地移动,保持粘在文本框的底部。

当然,行本身也必须调整其高度。

有时候没有要显示的图像,在这种情况下图像视图不应该是可见的。

这是它应该如何呈现,当它正常工作:

enter image description here

当前实现

行是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,有尽快的显示问题的一个或几个行的图像中有一个形象视图。

削波文

有时文本进行裁剪,可能是因为空图像视图被遮蔽文本的底部:

普通

enter image description here

削波

enter image description here

重要:调整表触发重绘并修复显示问题...

我已经试过

单元复用

我认为主要问题是因为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图像

我试图去除图像视图,且具有图像添加在文本视图,而不是归因字符串的结尾。但是结果通常很糟糕,而且在大多数情况下它不起作用(例如,无法及时下载图像以将其添加到属性字符串中,使单元格根本没有文本或图像并在错误的高度)。

问题

我在做什么错?我怎样才能解决这些问题?我的猜测是我应该改变自动布局约束,但我没有看到一个可行的解决方案。

或者你可能会完全不同吗?

+0

你在说'NSTextView'和你正在使用'NSTextField'的图片和代码。你有没有检查'nosbounds.size'在'heightOfRow'中是否正确? – Willeke

+0

Arf,我的错,我在测试的时候从NSTextView变成了NSTextField,并且忘记恢复原状了。你认为使用NSTextField是错误的,我应该回到NSTextView? // Woah,ns.bounds.size总是具有零高度......不知道发生了什么,是因为NSTextField而不是NSTextView? – Moritz

+0

我刚刚发现,这在macOS 10.12 Sierra中没有问题。错误的行为只发生在macOS 10.11 Mavericks ... oO – Moritz

文本字段在IB中具有“首选宽度”字段,允许调整固有大小与自动布局计算大小的关联。

将此IB属性值更改为“First Runtime Layout Width”或“Explicit”通常有助于解决类似问题。

enter image description here

这解决了过去我的很多问题。

+0

这解决了小牛的问题,似乎并没有改变塞拉利昂的任何事情。非常感谢,尤金! :) – Moritz