Как прошить пользовательское представление NSMenuItem после выбора? - PullRequest
2 голосов
/ 01 февраля 2011

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

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

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

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

Ответы [ 3 ]

3 голосов
/ 22 августа 2012

Я знаю, что этому больше года, но это был первый хит в моем поиске в 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]];
}
1 голос
/ 29 ноября 2016

На самом деле можно сделать так, чтобы ваш пользовательский вид флэш-памяти был похож на обычный 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, возможно, стоит взглянуть.

0 голосов
/ 10 марта 2015

Вот мой код, который мигает пользовательский пункт меню.

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