NSButton - 命中测试翻转/悬停自定义形状的按钮

时间:2015-01-13 01:24:32

标签: cocoa hittest nsbutton

(针对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。]

解决方案步骤:

  1. NSTrackingArea 添加到该按钮,并且(至少) NSTrackingMouseEnteredAndExited NSTrackingMouseMoved 选项。

  2. 实施 -hitTest:,以便按下按钮进行准确(例如循环)命中测试。我们不会在此处更改按钮的外观。

  3. 实施 -mouseEntered: -mouseExited:

  4. -mouseEntered 中进行(循环)碰撞检测,通过 -setImage:相应地更改按钮的外观(或以其​​他方式标记对绘图策略的更改) 。)

  5. -mouseExited:上将按钮的外观恢复为默认值。

  6. 但是, -mouseEntered: -mouseExited:不会连续调用。因此,我们还需要实现 -mouseMoved:

  7. 但是,我们必须在窗口上调用 -setAcceptsMouseMovedEvents:YES ,以便在按钮上调用 -mouseMoved:方法。

  8. 将(圆形)碰撞检测和外观更改添加到 -mouseMoved

2 个答案:

答案 0 :(得分:0)

使用NSTrackingArea是可行的方法,对于非矩形形状,您必须添加自定义代码以对自定义几何执行命中测试。

当鼠标悬停在您的形状上方时,您不清楚为什么要连续设置相同的图像?

无论如何,有mouseMoved:当鼠标在跟踪区域内移动时收到通知。 但是检查文档 - 您可能需要在视图或窗口上设置一些额外的标志,因为默认行为可能不会发送移动的消息,以防止在没有人监听的情况下使用大量消息阻塞框架..

答案 1 :(得分:0)

所以你确实想要使用跟踪区域和鼠标事件。这些可以帮助您了解您是否想要测试一下。

在大多数情况下,您实际上可能想要比图像稍大的区域。看起来更自然。

如果您的按钮是基于图像的,请使用此NSImage方法进行命中测试

hitTestRect:withImageDestinationRect:上下文:提示:翻转:

记住一个矩形可以是一个点的大小。

https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSImage_Class/index.html#//apple_ref/occ/instm/NSImage/hitTestRect:withImageDestinationRect:context:hints:flipped

如果您的按钮是基于路径的,NSBezierPath和CGPath有自己的包含点类型的解决方案。

在这里度过时间。这是人们在用户界面中拥有最多的体验之一,所以如果它不正确就会让人觉得笨重。