基于视图的 NSTableView 滚动性能

View-Based NSTableView Scrolling Performance

我有一个 NSTableView,它的父级是 NSMenuItem 的视图。 NSTableView 是一个基于视图的 table。我正在使用来自 NSArrayController 的数据绑定来填充 table。

NSTableView 的滚动性能很差。滚动功能似乎不是“连续”的,只有当我的手指离开触控板时才会滚动。这种行为有点像当你有一个文本字段时,它只在按下 return 键时发送它的动作,而不是连续发送动作。

如果我打开和关闭菜单的次数足够多,table 将平滑地滚动 NSTableView 的一部分,但很快就会恢复为不稳定的滚动。我也可以点击并拖动以相对平滑地有效滚动各行,但同样,双指滚动手势非常笨拙。

下面是如何填充 table 的代码。在 IB 中,文本字段绑定到名称 属性,NSImageView 绑定到名为 AmphRunningApp 的自定义 class 的图标 属性。

AmphRunningApp Class:

import Foundation
import Cocoa

class AmphRunningApp: NSObject
{
    @objc var app: NSRunningApplication
    @objc var name: String
    @objc var icon: NSImage

init(app: NSRunningApplication, name: String, icon: NSImage)
{
    self.name = name
    self.app = app
    self.icon = icon
}

填充 table:

@IBAction @objc func updateRunningAppsTable(sender: Any)
{
    // Get all currently running apps
    // and sort them alphabetically by localized name:
    
    let runningApps = NSWorkspace.shared.runningApplications.sorted
    {
        [=11=].localizedName! < .localizedName!
    }

    // For every running app,
    // add it to the array controller:
    
    for app in runningApps
    {
        var duplicateApp = false
        
        // Check that this app does not already exist in the array controller
        for dupeApp in self.menuRunningAppAC.arrangedObjects as! [AnyObject]
        {
            if dupeApp.name == app.localizedName
            {
                duplicateApp = true
            }
        }

        // If this app has not already been added
        // to the array controller, add it
        if duplicateApp == false
        {
            self.menuRunningAppAC.addObject(AmphRunningApp(app: app, name: app.localizedName!, icon: app.icon!))
        }
    }

    self.statusMenuAppTable.reloadData()
}

这个问题似乎与 NSStatusItem 的按钮 属性 和 GCD 上的 performClick() 功能有关。如果我简单地为我的 NSStatusItem 分配一个菜单(然后通过单击打开它(即 left-click 或 right-click),滚动会非常平滑。如果我不使用 GCD 调用 performClick( ) 功能,滚动也非常顺畅。**

JACKED-UP 笨拙的滚动:

@objc func statusItemClicked(_ sender: Any?)
{
    NSApp.activate(ignoringOtherApps: true)

    if (NSApp.currentEvent != nil)
    {
        print("right click")
        let event = NSApp.currentEvent!

        if event.type == NSEvent.EventType.rightMouseUp || event.modifierFlags.contains(.control) // RIGHT-CLICK
        {
            

            // THIS IS THE PROBLEM:
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.01)
            {
                self.statusItem.menu = self.statusItemMenu
                self.statusItem.button?.performClick(nil)
            }
            // END PROBLEM


        }
        else // LEFT-CLICK
        {
            print("left click")
        }
}



BUTTERY-SMOOTH 滚动:

@objc func statusItemClicked(_ sender: Any?)
{
    NSApp.activate(ignoringOtherApps: true)

    if (NSApp.currentEvent != nil)
    {
        print("right click")
        let event = NSApp.currentEvent!

        if event.type == NSEvent.EventType.rightMouseUp || event.modifierFlags.contains(.control) // RIGHT-CLICK
        {
            self.statusItem.menu = self.statusItemMenu
            self.statusItem.button?.performClick(nil)
        }
        else // LEFT-CLICK
        {
            print("left click")
        }
}