Macos 在NSTextView上更改NSView的NSCursor

Macos 在NSTextView上更改NSView的NSCursor,macos,swift,cocoa,Macos,Swift,Cocoa,发现了一个与我类似的问题, 但我的问题似乎更多地与视图层次结构有关 我有一个NSTextView,然后作为同级视图,它上面还有几个其他NSVIEW 与上面链接的问题类似,我设置了一个跟踪区域,并按如下方式应用光标: class CursorChangingView: NSView { override func updateTrackingAreas() { let trackingArea = NSTrackingArea(rect: } overr

发现了一个与我类似的问题, 但我的问题似乎更多地与视图层次结构有关

我有一个NSTextView,然后作为同级视图,它上面还有几个其他NSVIEW

与上面链接的问题类似,我设置了一个跟踪区域,并按如下方式应用光标:

class CursorChangingView: NSView {
    override func updateTrackingAreas() {
        let trackingArea = NSTrackingArea(rect: 
    }

    override func cursorUpdate(event: NSEvent) {
        NSCursor.arrowCursor().set()
    }
}
它在悬停时似乎可以工作,但会立即返回到,这是此光标或更改视图下NSTextView的默认光标


这是在将光标悬停在某个NSView上时应用更改光标的正确方法吗?它下面的NSTextView是否覆盖了我的覆盖?

您所需要的只是对自定义视图进行子类化,覆盖awakeFromNib方法,为[.mouseMoved,.activeAlways]事件添加自定义跟踪区域:那里。无需覆盖
resetCursorRects
和/或
updateTrackingAreas
。您只需重写mouseMoved方法并在其中设置所需的光标:

关于
discardCursorRects
方法的说明:

从文件中

您永远不需要直接调用此方法

Xcode 9•Swift 4

import Cocoa

class CursorChangingView: NSView {

    override func awakeFromNib() {

        addTrackingArea(NSTrackingArea(rect: bounds, options: [.activeAlways, .mouseMoved], owner: self, userInfo: nil))

        wantsLayer = true
        layer?.backgroundColor = NSColor.cyan.cgColor
        layer?.borderColor = NSColor.black.cgColor
        layer?.borderWidth = 1
    }

    @objc override func mouseMoved(with theEvent: NSEvent) {
        NSCursor.pointingHand.set()
    }
}

谢谢@Leo Dabus的回答, 但是我成功地解决了这个问题,所以我也会发布我的答案

在我的例子中,由于某种原因,
mouseEntered
mouseEntered
根本不起作用

下面是我的代码,它最终实现了:

class CursorChangingView: NSView {
    let trackingArea: NSTrackingArea?
    func setupTracking() {
        if self.trackingArea == nil {
            self.trackingArea = NSTrackingArea(rect: self.bounds, options: NSTrackingAreaOptions.ActiveAlways | NSTrackingAreaOptions.MouseMoved | NSTrackingAreaOptions.CursorUpdate | NSTrackingAreaOptions.MouseEnteredAndExited | NSTrackingAreaOptions.ActiveInActiveApp, owner: self, userInfo: nil)
            self.addTrackingArea(self.trackingArea!)
        }
    }

    override func updateTrackingAreas() {
        self.trackingArea = NSTrackingArea(rect: self.bounds, options: NSTrackingAreaOptions.ActiveAlways | NSTrackingAreaOptions.CursorUpdate | NSTrackingAreaOptions.MouseEnteredAndExited | NSTrackingAreaOptions.ActiveInActiveApp, owner: self, userInfo: nil)
        self.addTrackingArea(self.trackingArea!)
    }

    override func resetCursorRects() {
        self.discardCursorRects()
        self.addCursorRect(self.bounds, cursor: NSCursor.arrowCursor())
    }

    override func mouseMoved(theEvent: NSEvent) {
        NSCursor.arrowCursor().set()
    }
}
这可能有点过分,但有效,因此我将把它作为我自己的解决方案与大家分享。

一些重要注意事项:

  • mouseMoved
    或类似事件上调用
    super
    时要小心,否则光标可能会被基类实现重置
  • 仅在父视图大小更改时重置跟踪区域;如果您试图通过覆盖
    layout()
    来实现这一点,那么这种情况将一直发生,这并不好
下面是一个示例类,您可以将其用作故事板中的基类

Swift 4代码:

import Cocoa

final class MouseTrackingTextView: NSTextView {

    // MARK: - Lifecycle

    override func awakeFromNib() {
        setupTrackingArea()
    }

    // MARK: - Resizing

    // Call this in your controller's `viewDidLayout`
    // so it only gets called when the view resizes
    func superviewResized() {
        resetTrackingArea()
    }

    // MARK: - Mouse Events

    override func resetCursorRects() {
        addCursorRect(bounds, cursor: cursorType)
    }

    override func mouseMoved(with event: NSEvent) {
        cursorType.set()
    }

    // MARK: - Private Properties

    private var currentTrackingArea: NSTrackingArea?

    private var cursorType: NSCursor {
        return isEditable ? .iBeam : .pointingHand
    }

    // MARK: - Private API

    private func setupTrackingArea() {
        let trackingArea = NSTrackingArea(rect: bounds,
                                          options: [.activeAlways, .mouseMoved],
                                          owner: self, userInfo: nil)
        currentTrackingArea = trackingArea
        addTrackingArea(trackingArea)
    }

    private func resetTrackingArea() {
        if let trackingArea = currentTrackingArea {
            removeTrackingArea(trackingArea)
        }
        setupTrackingArea()
    }

}

在我的例子中,当
CursorChangingView
位于
NSTextView
上方时,此选项仍会闪烁。你是怎么摆脱的?还有,第二次创建跟踪时,你不再跟踪
。mouseMoved
对我不起作用。如果自定义视图下面的文本字段具有first responder,则光标仍会更改回IBeam