Swift3 Cocoa NSTrackingAreaを使ってView上のマウスの移動を検出する

cocoaswifttracking areaの設定とイベント捕捉。

方法はいくつかあると思いますが、そのうちの1つをメモ。

大雑把な流れは次の通り。

  1. 下地のView(マウスを捕捉したい部分のView)をカスタムViewにする
  2. 上のカスタムViewにトラッキングエリアを保持させ、生成する
  3. トラッキングの設定を行う
  4. マウスイベントを実装する
  5. 必要に応じてリサイズなどにも対応する
  6. サンプルプロジェクト(GitHub)

1は単純にViewを新しく作成するか、すでにカスタムViewであればそのファイルに追記するだけでいい。ファイルを用意したら、下のようにStoryBoardで対象のViewにカスタムクラスの設定をする。

SS20171010 03908

2はフィールドを持たせればいい。

var mouseTrackingArea: NSTrackingArea?

なお、このmouseTrackingAreaの生成タイミングはviewDidMoveToWindowにした。例は以下。

override func viewDidMoveToWindow() {
    super.viewDidMoveToWindow()

    // mouseTrackingAreaをセットアップ
    updateTrackingArea()
}

3は監視したいイベント(move, downなど)をトラッキングエリアとして追加する。下のようにする。

func updateTrackingArea() {
    if let ta = mouseTrackingArea {
        if ta.rect == visibleRect {
            // 監視しているエリアサイズに変更がなければ何もしない
            return
        } else {
            // サイズが変わっていたら以前のエリアを削除
            removeTrackingArea(ta)
        }
    }

    // 新しいエリアを設定
    // 監視するイベントを指定
    let options: NSTrackingAreaOptions = [
        NSTrackingAreaOptions.mouseMoved,
        NSTrackingAreaOptions.activeInKeyWindow
    ]
    mouseTrackingArea = NSTrackingArea(
        rect: visibleRect, options: options, owner: self, userInfo: nil)
    addTrackingArea(mouseTrackingArea!)
}

4NSViewmouseMovedなどを実装すればいい。例は以下。

override func mouseMoved(with event: NSEvent) {
    // 何かする
    let location = event.locationInWindow
    let inforect = textField.frame

    if inforect.contains(location) {
        textField.stringValue = "Mouse is on the label!"
    } else {
        textField.stringValue = "Mouse location: \(location)"
    }

    super.mouseMoved(with: event)
}

5NSViewviewDidEndLiveResizeを実装すればいい。

override func viewDidEndLiveResize() {
    super.viewDidEndLiveResize()

    // リサイズが行われたらトラッキングエリアを更新
    updateTrackingArea()
}

サンプルプロジェクトはこちら。 ikapper/cocoa-sample-trackingarea

タイトルとURLをコピーしました