当图像插入一行时,NSTextField 在 NSTableView 中变得模糊

NSTextField is blurry in NSTableView when image is inserted in a row

在我基于视图的 NSTableView 中,每个视图都有一个 NSTextField 和一个位于文本字段正下方的 NSImageView。

有时,当我在 table 的顶部插入一个新行时,该行的 NSImageView 中有一个图像, 其他行中的文本 变为 blurry/degraded.

滚动几次后文字又正常了

不行:

好的:

文本仅在行之后带有图像的行模糊的示例:

这真的让我觉得这是来自 .insertRowsnoteHeightOfRows 的问题。

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

滚动视图在IB中设置了CoreAnimation层。我在准备单元格时也使用了层:

cell.layer?.isOpaque = true
cell.textLabel.layer?.isOpaque = true

有时

cell.layer?.borderColor = someColor
cell.layer?.borderWidth = someWidth

行插入:

// update the model, then:
NSAnimationContext.runAnimationGroup({ (context) in
    context.allowsImplicitAnimation = true
    self.table.insertRows(at: index, withAnimation: [.effectGap])
})

正在用图像更新行:

// in tableViewCell, while populating the table
cell.postImage.image = img
cell.postImage.needsDisplay = true  

// once the image is downloaded
table.reloadData(forRowIndexes: ..., columnIndexes: ...)
table.noteHeightOfRows(withIndexesChanged: ...)

如何避免这个问题?很难调试,因为它并不总是发生,而且我看不出它发生时发生的原因。

由于文本只有在插入图像时才会变得模糊,我的第一个想法是 NSTextField 的框架不是 "integral"(它的像素值不是整数)。这是导致文本模糊的众所周知的原因。

您正在使用 Cocoa 的自动布局功能,所以我的建议是覆盖基于视图的 table 视图单元格中的 void layout() 方法。

调用它的 super 方法(让 Cocoa 进行所有需要的布局计算)并且只是将 textFiled 的框架设置为相同的框架,但不可分割。


附录:虽然 textField 本身可能有一个完整的框架 - 它仍然可以布置在 "half pixel"(在实际屏幕坐标中)上,这仍然会导致模糊。

TextField 是单元格的子视图,因此它的框架不在屏幕坐标中,而是在单元格坐标中。

示例:假设单元格有一个 (0.5, 0.5 , 100, 100) 的框架,它不是完整的,而 textField 有一个 (10,10, 50, 50) 的完整框架,它无论如何都是完整的!

但是当 textField 将在屏幕上布局时,它将具有以下框架:(10.5, 10.5, 50, 50) 这不是完整的 - 并且会导致在 "half pixel" 上绘制 textField(不是完整的) 导致文本模糊。

因此,在您的情况下,单元格本身必须与文本字段一起布置在一个整体框架上,以确保文本字段在屏幕坐标中位于整体框架上。


在您的 tableViewCell 子类中:

void layout()
{
    [super layout];

     //**** We have to ensure that the cell is also layed on an integral frame ****//

    [self setFrame:NSIntegralRect(self.frame)];

    //At this point after calling the [super layout]; myTextField will have a valid (autolayoutwise) frame so all you have to do is to ensure that it is indeed an integral frame doing so by calling NSIntegralRect(NSRect rect); method of Cocoa framework.
    [myTetxField setFrame:NSIntegralRect(myTextField.frame)];

    //Maybe optionally you will want to set everything to the integral rect :-)
    /*
    for(NSView * view in self.subViews)
    {
         [view setFrame:NSIntegralRect(view.frame)];
    }
    */
}