NSTableView 选择的行在使用箭头键滚动时闪烁

NSTableView selected row flickering while scrolling with arrow keys

我有一个基于 NSTableView 的视图,无法弄清楚如何解决在使用箭头键向上或向下滚动时当前选定的行闪烁的视觉故障。

所选行应 'glued' 显示在视图的顶部或底部,具体取决于滚动方向。 Finder 在列表视图中显示了这种正确的行为,但常规 table 视图似乎不是开箱即用的这种方式。我对为什么会这样感到困惑,并且没有明显的方法来规避它。谁能指出可能的原因/解决方案?

编辑1号

默认情况下,基于单元格的 NSTableView 以所需的方式运行,因此这可能是基于视图的实现所特有的错误。不过,出于不相关的原因,我不想使用基于单元格的 table。

编辑2号

我试过支持 table 视图的父视图层,以及拦截向上/向下箭头键击来进行我自己的滚动,但到目前为止我还没有能够消除闪烁.

编辑3号

我创建了一个小的 sample project 来重现该问题。

您尝试过更改视图吗?

scrollView.wantsLayer = true

如果您使用了 Interface Builder:

Select 滚动视图 打开 View Effects Inspector(或按 Cmd-Opt-8) 在 table 中,找到您的滚动视图所在的行并选中该框。

看起来选择发生了变化,旧的和新的选定行都被重新绘制了。接下来选定的行是动画 up/down。禁用滚动动画可以解决此问题。可以通过继承 NSClipView 并覆盖 scroll(to:).

来禁用滚动动画
override func scroll(to newOrigin: NSPoint) {
    setBoundsOrigin(newOrigin)      
}

它可能有一些副作用。

编辑

从 zrzka 的解决方案中复制,并进行了一些调整。使用向上箭头或向下箭头键时,滚动动画暂时被禁用。

class TableView: NSTableView {

    override func keyDown(with event: NSEvent) {
        if let clipView = enclosingScrollView?.contentView as? ClipView,
            (125...126).contains(event.keyCode) && // down arrow and up arrow
            event.modifierFlags.intersection([.option, .shift]).isEmpty {
            clipView.isScrollAnimationEnabled = false
            super.keyDown(with: event)
            clipView.isScrollAnimationEnabled = true
        }
        else {
            super.keyDown(with: event)
        }
    }
    
}

class ClipView: NSClipView {

    var isScrollAnimationEnabled: Bool = true
    
    override func scroll(to newOrigin: NSPoint) {
        if isScrollAnimationEnabled {
            super.scroll(to: newOrigin)
        } else {
            setBoundsOrigin(newOrigin)
            documentView?.enclosingScrollView?.flashScrollers()
        }
    }
    
}