Macos 在基于视图的NSTableView中,NSTextField由NSImageView剪裁
TL;博士: 在macOS 10.11中,一种基于视图的NSTableView,包含一个NSTextField和一个位于textfield正下方的NSImageView,其中一些行有图像,而另一些行没有图像,一些文本在向下滚动表格然后向上滚动后被剪裁 滚动前: 滚动后: 当我说“clipped”时,它意味着文本视图处于自动布局定义的最小高度,此时它应该展开。 请注意,这种错误行为只发生在MacOS10.11Mavericks中。macOS 10.12 Sierra没有此类问题Macos 在基于视图的NSTableView中,NSTextField由NSImageView剪裁,macos,cocoa,autolayout,nstableview,nstextfield,Macos,Cocoa,Autolayout,Nstableview,Nstextfield,TL;博士: 在macOS 10.11中,一种基于视图的NSTableView,包含一个NSTextField和一个位于textfield正下方的NSImageView,其中一些行有图像,而另一些行没有图像,一些文本在向下滚动表格然后向上滚动后被剪裁 滚动前: 滚动后: 当我说“clipped”时,它意味着文本视图处于自动布局定义的最小高度,此时它应该展开。 请注意,这种错误行为只发生在MacOS10.11Mavericks中。macOS 10.12 Sierra没有此类问题 上下文 ma
上下文 macOS 10.11+,基于视图的NSTableView 每行有一个文本字段,文本字段下方有一个图像视图 所有图元都在IB中设置了自动布局约束 目标 文本视图必须垂直调整其高度-图像视图应相应地移动,保持与文本字段底部的粘合 当然,行本身也必须调整其高度 有时没有要显示的图像,在这种情况下,图像视图不应可见 这是它正常工作时的渲染方式: 当前实施 该行是NSTableCellView的子类 在单元格中,文本字段设置为属性字符串 在
tableView(tableView:NSTableView,heightOfRow row:Int)->CGFloat
中,我创建了一个虚拟textView,用于查找实际textfield的高度,并相应地返回一个修改后的行高。我还检查是否有图像要显示,如果是这样,我将图像高度添加到行高度
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(\utableview:NSTableView,viewfortablecolumn:NSTableColumn?,row:Int)->NSView?
I准备实际单元格内容:
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(u-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层,但我几乎看不到任何区别
A/B测试
如果我完全删除imageView,只处理文本字段,一切正常。拥有imageView肯定是这里出现问题的原因
自动布局
我曾尝试在不使用自动布局的情况下处理行内容的显示,但没有效果。我也尝试过设置不同的约束,但很明显,我不擅长自动布局,也没有找到一个好的替代当前约束的方法
备选方案:带有图像的NSAttributedString
我尝试删除图像视图,并将图像添加到文本视图中属性字符串的末尾。但是,当它工作时,结果往往是丑陋的——而且在大多数情况下,它就是不工作(例如,当图像无法及时下载并添加到属性字符串中时,使单元格完全没有文本或图像,并且高度错误)
问题:
我做错了什么?我如何解决这些问题?我的猜测是,我应该更改自动布局约束,但我看不到有效的解决方案
或者您会完全不同地执行此操作吗?文本字段在IB中有“首选宽度”字段,允许调整内部大小与自动布局计算大小的相关性
将此IB属性值更改为“First Runtime Layout Width”或“Explicit”通常有助于解决类似问题
这解决了我过去的许多问题。您正在谈论的是
NSTextView
以及您正在使用的NSTextField
图片和代码。您是否检查了ns.bounds.size
在heightOfRow
中是否正确?Arf,是我的错,我在测试时从NSTextView更改为NSTextField,但忘了恢复。您是否认为使用NSTextField是错误的,我应该返回NSTextView?//哇,ns.bounds.size的高度始终为零。。。不确定发生了什么,是因为NSTextField而不是NSTextView吗?我刚刚发现这在macOS 10.12中没有问题。错误的行为只发生在MacOS10.11Mavericks中。。。oo您的文本字段有一个“首选宽度”。你的IB屏幕截图显示你已经将其设置为自动。你玩过其他价值观吗?无论是在IB还是在运行时。你也玩过指数变化的RowswithIndexChanged的NoteHeightofRowswithIndexChanged。自动布局可能需要再次调用您的代理。有些人称之为自动布局魔术。其他人则将其视为自动布局戏剧。这里真的没有什么可补充的。我的应用程序中有几个地方出现了类似的问题,它解决了这个问题。我认为这与auto layout计算约束的顺序以及文本字段具有固有大小的事实有关。这解决了Mavericks中的问题,并且似乎不会改变Sierra中的任何内容。非常感谢,尤金!:)