LoginSignup
4
3

More than 3 years have passed since last update.

[macOS][Swift5.3]マウスカーソルの画像をカスタマイズする方法

Last updated at Posted at 2021-02-28

macアプリでプリセット以外のカーソルを表示する方法を見つけるのに時間がかかったため、誰かの役に立てばと思い書き記します。

1. 環境

macOS: 11.2.1 Big Sur
Swift: 5.3.2
Xcode: 12.4

2. 全コード

TestView.swift
import Cocoa

class TestView: NSView {

    private var trackingArea: NSTrackingArea?

    override func updateTrackingAreas() {
        super.updateTrackingAreas()
        if self.trackingArea != nil {
            self.removeTrackingArea(self.trackingArea!)
            self.trackingArea = nil
        }
        let options: NSTrackingArea.Options = [.mouseMoved, .mouseEnteredAndExited, .activeAlways]
        let rect = NSRect(origin: .zero, size: self.frame.size)
        self.trackingArea = NSTrackingArea(rect: rect, options: options, owner: self, userInfo: nil)
        self.addTrackingArea(self.trackingArea!)
    }

    override func mouseEntered(with event: NSEvent) {
        let image = NSImage(named: "image_name")
        let cursor = NSCursor(image: image!, hotSpot: .zero)
        addCursorRect(self.bounds, cursor: cursor)
    }

    override func mouseExited(with event: NSEvent) {
        NSCursor.arrow.set()
    }

}

3. 解説

対象のNSView自身と同じ大きさのトラッキング範囲を作成し、カーソルが出入りするとイベントを発火するようにします。

    private var trackingArea: NSTrackingArea?

    override func updateTrackingAreas() {
        super.updateTrackingAreas()
        if self.trackingArea != nil {
            self.removeTrackingArea(self.trackingArea!)
            self.trackingArea = nil
        }
        let options: NSTrackingArea.Options = [.mouseEnteredAndExited, .activeAlways]
        let rect = NSRect(origin: .zero, size: self.frame.size)
        self.trackingArea = NSTrackingArea(rect: rect, options: options, owner: self, userInfo: nil)
        self.addTrackingArea(self.trackingArea!)
    }

カーソルがトラッキング範囲に入ったタイミングでカスタムカーソルを表示します。プリセットのカーソルではset()メソッドを使いますが、カスタムの場合addCursorRect()を使う必要があります。

    override func mouseEntered(with event: NSEvent) {
        let image = NSImage(named: "image_name")
        let cursor = NSCursor(image: image!, hotSpot: .zero)
        addCursorRect(self.bounds, cursor: cursor)
    }

上のコードの"hotSpot"は、カーソルの中でクリックを検知する座標を表します。矢印型のカーソルならばhotSpotを座標の左上に設定することで、見た目と動作を一致させることができます。

カーソルがトラッキング範囲を出たらデフォルトのカーソルに戻します。

    override func mouseExited(with event: NSEvent) {
        NSCursor.arrow.set()
    }

4. 参考資料

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3