无法实现macOS Quicklook中NSButton的悬停等状态效果
我需要实现QuickLook中按钮的三种状态:
- 空闲(Idle):浅灰色圆角边框,白色背景,黑色文字
- 悬停(Hover):浅蓝色填充背景,浅灰色圆角边框,黑色文字
- 激活(Active):深蓝色填充背景,白色文字
目前我只能实现空闲和激活状态,悬停时完全没有响应,尝试了各种设置都没用,我的代码如下:
let button = NSButton(title: "Test", target: nil, action: nil) button.bezelStyle = .toolbar button.isBordered = true
解决方法
方法1:自定义NSButtonCell绘制悬停状态
默认的.toolbar样式按钮在部分场景下不会自动触发悬停效果,你可以通过自定义NSButtonCell来手动绘制悬停状态:
class HoverToolbarButtonCell: NSButtonCell { override func draw(withFrame cellFrame: NSRect, in controlView: NSView) { super.draw(withFrame: cellFrame, in: controlView) // 判断鼠标是否悬停在按钮区域 guard let window = controlView.window, let event = window.currentEvent, event.type == .mouseMoved else { return } let mousePos = controlView.convert(window.mouseLocationOutsideOfEventStream, from: nil) let isHover = cellFrame.contains(mousePos) && !isHighlighted if isHover { // 绘制符合QuickLook样式的悬停背景 let hoverFrame = cellFrame.insetBy(dx: 1, dy: 1) NSColor.systemBlue.withAlphaComponent(0.2).setFill() NSBezierPath(roundedRect: hoverFrame, xRadius: 4, yRadius: 4).fill() } } } // 给按钮设置自定义Cell let button = NSButton(title: "Test", target: nil, action: nil) button.bezelStyle = .toolbar button.isBordered = true button.cell = HoverToolbarButtonCell()
方法2:用NSHoverGestureRecognizer监听悬停
给按钮添加悬停手势,手动切换样式,这种方式更灵活:
// 创建按钮 let button = NSButton(title: "Test", target: nil, action: nil) button.bezelStyle = .toolbar button.isBordered = true button.wantsLayer = true button.layer?.cornerRadius = 4 // 匹配QuickLook的圆角 // 添加悬停手势 let hoverGesture = NSHoverGestureRecognizer(target: self, action: #selector(handleButtonHover(_:))) button.addGestureRecognizer(hoverGesture) // 处理悬停事件 @objc private func handleButtonHover(_ gesture: NSHoverGestureRecognizer) { guard let button = gesture.view as? NSButton else { return } switch gesture.state { case .began, .changed: // 应用悬停样式 button.layer?.backgroundColor = NSColor.systemBlue.withAlphaComponent(0.2).cgColor case .ended, .cancelled: // 恢复空闲样式 button.layer?.backgroundColor = NSColor.clear.cgColor default: break } }
关键注意点
- 确保按钮所在的父视图开启了鼠标移动事件接收:
yourParentView.acceptsMouseMovedEvents = true - 如果是在NSToolbar中使用,建议将按钮放在自定义NSToolbarItem的
view属性中,避免Toolbar默认样式的干扰。
内容的提问来源于stack exchange,提问作者lenyapugachev
相关产品推荐
相关产品推荐

