You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在macOS SwiftUI视图中无需点击拖拽即可获取鼠标光标位置

实现方案

macOS 平台下 SwiftUI 原生没有提供鼠标悬停移动的直接手势,你可以通过封装 NSView 自带的追踪区域能力实现需求,最终效果和你用 DragGesture 获取的坐标体系完全一致,无需点击或拖拽操作即可触发。


完整可运行代码

import SwiftUI

// 自定义鼠标追踪视图
struct MouseTrackingView: NSViewRepresentable {
    // 坐标回调
    var onMouseMove: (CGPoint) -> Void
    
    func makeNSView(context: Context) -> TrackingNSView {
        let view = TrackingNSView()
        view.onMouseMove = onMouseMove
        return view
    }
    
    func updateNSView(_ nsView: TrackingNSView, context: Context) {
        nsView.onMouseMove = onMouseMove
    }
    
    // 内部实现追踪能力的NSView
    class TrackingNSView: NSView {
        var onMouseMove: ((CGPoint) -> Void)?
        private var trackingArea: NSTrackingArea?
        
        override func updateTrackingAreas() {
            super.updateTrackingAreas()
            // 移除旧的追踪区域避免重复监听
            if let oldArea = trackingArea {
                removeTrackingArea(oldArea)
            }
            // 创建新的追踪区域,监听鼠标移动、视图尺寸变化自动更新
            let newArea = NSTrackingArea(
                rect: bounds,
                options: [.activeInKeyWindow, .mouseMoved, .inVisibleRect],
                owner: self,
                userInfo: nil
            )
            addTrackingArea(newArea)
            trackingArea = newArea
        }
        
        override func mouseMoved(with event: NSEvent) {
            super.mouseMoved(with: event)
            // 将系统鼠标坐标转换为当前视图的本地坐标,和DragGesture返回格式完全一致
            let location = convert(event.locationInWindow, from: nil)
            // 仅当鼠标在视图范围内时返回坐标
            guard bounds.contains(location) else { return }
            onMouseMove?(location)
        }
        
        // 可选实现:鼠标移出视图后重置坐标
        override func mouseExited(with event: NSEvent) {
            super.mouseExited(with: event)
            onMouseMove?(.zero)
        }
    }
}

// 扩展View简化调用方式
extension View {
    func onMouseMove(perform action: @escaping (CGPoint) -> Void) -> some View {
        self.background(MouseTrackingView(onMouseMove: action))
    }
}

// 改造后的你的业务视图
struct ContentView: View {
    @State private var location: CGPoint = .zero
    
    var body: some View {
        VStack {
            Spacer()
            HStack {
                Spacer()
                Text("location is: ( \(location.x), \(location.y))").bold()
                Spacer()
            }
            Spacer()
        }
        .background(Color.yellow)
        // 替换原来的DragGesture直接调用即可
        .onMouseMove { location in
            self.location = location
        }
    }
}

效果演示

效果展示图

内容的提问来源于stack exchange,提问作者swiftPunk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 11:48:00