我需要为NSMenuItem指定一个视图并进行一些自定义绘图。基本上,我在当前所选菜单项旁边添加了一个小删除按钮等等。但是我希望我的自定义菜单项看起来像所有其他方式的常规菜单项。根据文件:
带有视图的菜单项不会绘制 它的标题,状态,字体或其他 标准图纸属性,和 分配绘图责任 完全是为了观点。
好的,所以我不得不复制状态列和选择渐变的外观,这并不难。我遇到问题的部分是选择后菜单项“闪烁”或“闪烁”的方式。我正在使用NSTimer试图模仿这个小动画,但它感觉不舒服。它眨眼了多少次?我应该使用什么时间间隔?我已经进行了很多实验,感觉很糟糕。
之前有没有人这样做过,或者对如何在菜单项中添加按钮有其他建议?也许应该有一个堆栈交换网站只是为了定制可可绘图......
答案 0 :(得分:3)
我知道这已经超过一年了,但这是我在Google搜索中的第一次曝光并没有得到答复,所以我为那些仍在寻找解决方案的人发布了我的答案。
对于我的应用程序,我使用Core Animation和NSMenuItem视图的自定义NSView。我创建了一个新的图层支持视图,设置背景颜色,并将其添加到我的自定义视图中。然后我为图层(闪烁部分)设置了动画。然后在-(void) animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
回调中,我删除了叠加层并关闭了菜单。这与默认的NSMenu闪存不完全匹配,但我想要一个37Signals / Stack Overflow Yellow Fade Technique,所以它对我有用。这是代码:
-(void) mouseUp:(NSEvent *)theEvent {
CALayer *layer = [CALayer layer];
[layer setDelegate:self];
[layer setBackgroundColor:CGColorCreateGenericRGB(0.0, 0.0, 1.0, 1.0)];
selectionOverlayView = [[NSView alloc] init];
[selectionOverlayView setWantsLayer:YES];
[selectionOverlayView setFrame:self.frame];
[selectionOverlayView setLayer:layer];
[[selectionOverlayView layer] setNeedsDisplay];
[selectionOverlayView setAlphaValue:0.0];
[self addSubview:selectionOverlayView];
CABasicAnimation *alphaAnimation1 = [CABasicAnimation animationWithKeyPath: @"alphaValue"];
alphaAnimation1.beginTime = 0.0;
alphaAnimation1.fromValue = [NSNumber numberWithFloat: 0.0];
alphaAnimation1.toValue = [NSNumber numberWithFloat: 1.0];
alphaAnimation1.duration = 0.07;
CABasicAnimation *alphaAnimation2 = [CABasicAnimation animationWithKeyPath: @"alphaValue"];
alphaAnimation2.beginTime = 0.07;
alphaAnimation2.fromValue = [NSNumber numberWithFloat: 1.0];
alphaAnimation2.toValue = [NSNumber numberWithFloat: 0.0];
alphaAnimation2.duration = 0.07;
CAAnimationGroup *selectionAnimation = [CAAnimationGroup animation];
selectionAnimation.delegate = self;
selectionAnimation.animations = [NSArray arrayWithObjects:alphaAnimation1, alphaAnimation2, nil];
selectionAnimation.duration = 0.14;
[selectionOverlayView setAnimations:[NSDictionary dictionaryWithObject:selectionAnimation forKey:@"frameOrigin"]];
[[selectionOverlayView animator] setFrame:[selectionOverlayView frame]];
}
-(void) animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
[selectionOverlayView removeFromSuperview];
NSMenuItem *enclosingMenuItem = [self enclosingMenuItem];
NSMenu *enclosingMenu = [enclosingMenuItem menu];
[enclosingMenu cancelTracking];
[enclosingMenu performActionForItemAtIndex:[enclosingMenu indexOfItem:enclosingMenuItem]];
}
答案 1 :(得分:0)
这是我的代码闪烁自定义菜单项。
int16_t fireTimes;
BOOL isSelected;
- (void)mouseEntered:(NSEvent*)event
{
isSelected = YES;
}
- (void)mouseUp:(NSEvent*)event {
fireTimes = 0;
isSelected = !isSelected;
[self setNeedsDisplay:YES];
NSTimer *timer = [NSTimer timerWithTimeInterval:0.05 target:self selector:@selector(animateDismiss:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode];
}
-(void)animateDismiss:(NSTimer *)aTimer
{
if (fireTimes <= 2) {
isSelected = !isSelected;
[self setNeedsDisplay:YES];
} else {
[aTimer invalidate];
[self sendAction];
}
fireTimes++;
}
- (void)drawRect:(NSRect)dirtyRect {
if (isSelected) {
NSRect frame = NSInsetRect([self frame], -4.0f, -4.0f);
[[NSColor selectedMenuItemColor] set];
NSRectFill(frame);
[itemNameFld setTextColor:[NSColor whiteColor]];
} else {
[itemNameFld setTextColor:[NSColor blackColor]];
}
}
- (void)sendAction
{
NSMenuItem *actualMenuItem = [self enclosingMenuItem];
[NSApp sendAction:[actualMenuItem action] to:[actualMenuItem target] from:actualMenuItem];
NSMenu *menu = [actualMenuItem menu];
[menu cancelTracking];
// [self setNeedsDisplay:YES]; // I'm not sure of this
}
答案 2 :(得分:0)
实际上,您可以将自定义视图设置为常规NSMenuItem
,而无需手动实现动画。
注意:这使用私有API,并修复了与自定义视图相关的一些其他奇怪的NSMenuItem
怪癖。
<强> NSMenuItem.h 强>
#import <AppKit/AppKit.h>
@interface NSMenuItem ()
- (BOOL)_viewHandlesEvents;
@end
桥接标题
#import "NSMenuItem.h"
<强> MenuItem.swift 强>
class MenuItem: NSMenuItem {
override func _viewHandlesEvents() -> Bool {
return false
}
}
这个API确实应该是公开的,如果你不是为App Store开发的话,可能值得一看。