如何在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
相关产品推荐
相关产品推荐

