2011-02-01 4 views
1

Мне нужно назначить представление NSMenuItem и выполнить собственный пользовательский чертеж. В основном, я добавляю небольшую кнопку удаления рядом с выбранным в данный момент пунктом меню, между прочим. Но я хочу, чтобы мой пользовательский элемент меню выглядел и вел себя как обычный пункт меню другими способами. Согласно документу:Как прошивать пользовательский вид NSMenuItem после выбора?

Пункт меню с целью не рисует его название, состояние, шрифта или другие стандартных атрибутов рисования и правопреемников чертежных ответственности целика зрения.

Хорошо, поэтому мне пришлось дублировать внешний вид столбца состояния и градиента выбора, что было не так сложно. У меня возникла проблема с тем, как элемент меню «мигает» или «мигает» после его выбора. Я использую NSTimer, чтобы попытаться воспроизвести эту маленькую анимацию, но она просто отключена. Сколько раз он моргает? Какой промежуток времени я должен использовать? Я много экспериментировал, и он просто чувствует себя неловко.

Кто-нибудь сделал это раньше или имел другие предложения о том, как добавить кнопку в пункт меню? Может быть, должен быть сайт обмена стеками только для пользовательского рисунка какао ...

+0

Вы также должны мигать родителем menuitem в строке меню при нажатии клавиши быстрого вызова, если она есть. –

+0

Я ищу выбранный код градиента (или только начальный и конечный цвета), вы можете поделиться им? Заранее спасибо. –

ответ

3

Я знаю, что это уже не один год, но это был первый хит в моем поиске Google, и он остался без ответа, поэтому я отправляю свой ответ для тех, кто все еще ищет решение.

Для моего приложения я использовал Core Animation с пользовательским NSView для представления NSMenuItem. Я создал новый слой с поддержкой вида, установил цвет фона и добавил его к своему пользовательскому представлению. Затем я анимировал слой (мигающая часть). Затем в обратном вызове -(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]]; 
} 
+0

Отличный код для начала - здесь есть несколько проблем. Например, selectionOverlayView никогда не выпускается после того, как он выделен, так что память течет. Кроме того, вместо того, чтобы делать группу анимаций, вы можете просто сделать одну анимацию с атрибутом «autoreverses», установленным в true. Но в любом случае, спасибо за публикацию, это было очень полезно. – AriX

+0

Еще один год спустя (почти), и я ищу что-то подобное. Мне любопытно, есть ли у вас какие-либо улучшения в вашем коде, и если вы захотите поделиться классом образцов? Могу отправить мне по электронной почте свое имя пользователя в gmail. заранее спасибо – kdbdallas

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 
} 
0

Это на самом деле можно иметь свой пользовательский вид вспышки, как обычный NSMenuItem без реализации анимации вручную.

Примечание: здесь используется частный API, а также исправлено несколько других странных причуд NSMenuItem, связанных с пользовательскими видами.

NSMenuItem.h

#import <AppKit/AppKit.h> 

@interface NSMenuItem() 
    - (BOOL)_viewHandlesEvents; 
@end 

Bridging Заголовок

#import "NSMenuItem.h" 

MenuItem.swift

class MenuItem: NSMenuItem { 
    override func _viewHandlesEvents() -> Bool { 
     return false 
    } 
} 

Th API действительно должен быть общедоступным, и если вы не разрабатываете App Store, возможно, стоит взглянуть на него.

Смежные вопросы