fix: 用 NSTrackingArea 替代 .onHover 解决标题栏闪烁和红绿灯丢失问题

.onHover 在 macOS 上不可靠,鼠标离开后会误触发 true 导致标题栏短暂回来但没有红绿灯按钮。
改用 NSTrackingArea 的 mouseEntered/mouseExited 做可靠的鼠标追踪。
This commit is contained in:
yumoqing 2026-07-01 07:42:16 +08:00
parent ec8c3bd51c
commit fde83a87bc

View File

@ -223,6 +223,54 @@ class PlayerLayerHostView: NSView {
}
}
// MARK: - SwiftUI .onHover
struct MouseTrackingArea: NSViewRepresentable {
let onHoverChange: @MainActor (Bool) -> Void
func makeNSView(context: Context) -> MouseTrackingNSView {
let view = MouseTrackingNSView()
view.onHoverChange = onHoverChange
return view
}
func updateNSView(_ nsView: MouseTrackingNSView, context: Context) {
nsView.onHoverChange = onHoverChange
}
}
class MouseTrackingNSView: NSView {
var onHoverChange: (@MainActor (Bool) -> Void)?
private var trackingArea: NSTrackingArea?
private var isHovering = false
override func updateTrackingAreas() {
super.updateTrackingAreas()
if let existing = trackingArea {
removeTrackingArea(existing)
}
let area = NSTrackingArea(
rect: .zero,
options: [.mouseEnteredAndExited, .activeInKeyWindow, .inVisibleRect],
owner: self,
userInfo: nil
)
addTrackingArea(area)
trackingArea = area
}
override func mouseEntered(with event: NSEvent) {
guard !isHovering else { return }
isHovering = true
onHoverChange?(true)
}
override func mouseExited(with event: NSEvent) {
guard isHovering else { return }
isHovering = false
onHoverChange?(false)
}
}
// MARK: -
struct PlayerContentView: View {
@ObservedObject var bridge: PlayerBridge
@ -327,9 +375,9 @@ struct PlayerContentView: View {
}
}
}
.onHover { hovering in
.background(MouseTrackingArea(onHoverChange: { hovering in
setWindowTitleBarVisible(hovering)
}
}))
.onAppear {
// 绿
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {