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