(针对OS X 10.10,Xcode的最新版本)
我有一个 NSButton 子类。
按钮需要响应鼠标翻转/悬停,一个网页按钮。
按钮需要外观呈圆形。因此,使用圆形图形调用 -setImage:和 -setAlternateImage:。
问题1:当在NSButton的矩形内点击鼠标时,NSButton的默认行为会导致正面命中测试。这包括鼠标点击按钮的圆形区域之外。
建议的解决方案:覆盖 -hitTest:以计算点击按钮中心的距离。如果距离>按钮的半径,我们没有有效的点击。
好的,好的。这为我们提供了圆形按钮上鼠标点击的准确碰撞检测。问题2:如何处理鼠标悬停/翻转,并相应地更改按钮的外观。
建议的解决方案:在按钮上添加 NSTrackingArea ,然后覆盖 -mouseEntered:和 -mouseExited:,以便我们更改按钮当鼠标移过按钮时,image和alternateImage。
好的,好的。这适用于矩形。但是 ... NSTrackingArea 适用于矩形,而非任意区域,如圆圈。更糟糕的是,它不尊重-hitTest:
建议的解决方案:将圆形碰撞检测代码添加到 -mouseEntered:和 -mouseExited:
可是...
-mouseEntered:和 -mouseExited:仅在每个按钮的进入/退出时被称为ONCE,而不是连续的。这意味着如果将鼠标移动到按钮的矩形区域,但距离不足以使其进入按钮的圆形区域,则将调用 -mouseEntered:。但是在调用 -mouseExited:之后才会再次调用它。鼠标进一步移动到圆形区域将不起作用。 (不会发生翻转。)
即。使用这两种方法无法使用准确的鼠标位置信息不断更新按钮的状态。
问题:有没有人知道如何实现悬停并按下非矩形按钮?
[编辑 - 已解决感谢cacau。]
解决方案步骤:
将 NSTrackingArea 添加到该按钮,并且(至少) NSTrackingMouseEnteredAndExited 和 NSTrackingMouseMoved 选项。
实施 -hitTest:,以便按下按钮进行准确(例如循环)命中测试。我们不会在此处更改按钮的外观。
实施 -mouseEntered:和 -mouseExited:
在 -mouseEntered 中进行(循环)碰撞检测,通过 -setImage:相应地更改按钮的外观(或以其他方式标记对绘图策略的更改) 。)
在 -mouseExited:上将按钮的外观恢复为默认值。
但是, -mouseEntered:和 -mouseExited:不会连续调用。因此,我们还需要实现 -mouseMoved:
但是,我们必须在窗口上调用 -setAcceptsMouseMovedEvents:YES ,以便在按钮上调用 -mouseMoved:方法。
将(圆形)碰撞检测和外观更改添加到 -mouseMoved 。
答案 0 :(得分:0)
使用NSTrackingArea
是可行的方法,对于非矩形形状,您必须添加自定义代码以对自定义几何执行命中测试。
当鼠标悬停在您的形状上方时,您不清楚为什么要连续设置相同的图像?
无论如何,有mouseMoved
:当鼠标在跟踪区域内移动时收到通知。
但是检查文档 - 您可能需要在视图或窗口上设置一些额外的标志,因为默认行为可能不会发送移动的消息,以防止在没有人监听的情况下使用大量消息阻塞框架..
答案 1 :(得分:0)
所以你确实想要使用跟踪区域和鼠标事件。这些可以帮助您了解您是否想要测试一下。
在大多数情况下,您实际上可能想要比图像稍大的区域。看起来更自然。
如果您的按钮是基于图像的,请使用此NSImage方法进行命中测试
hitTestRect:withImageDestinationRect:上下文:提示:翻转:
记住一个矩形可以是一个点的大小。
如果您的按钮是基于路径的,NSBezierPath和CGPath有自己的包含点类型的解决方案。
在这里度过时间。这是人们在用户界面中拥有最多的体验之一,所以如果它不正确就会让人觉得笨重。