2

NSMenuItemにビューを割り当てて、カスタム描画を行う必要があります。基本的に、現在選択されているメニュー項目の横に小さな削除ボタンを追加しています。ただし、カスタムメニュー項目は、他のすべての点で通常のメニュー項目のように見え、動作するようにしたいと思います。ドキュメントによると:

ビューのあるメニュー項目は、そのタイトル、状態、フォント、またはその他の標準の描画属性を描画せず、描画の責任をビューに完全に割り当てます。

さて、状態列と選択勾配の外観を複製する必要がありましたが、それほど難しくはありませんでした。私が問題を抱えているのは、メニュー項目が選択された後の「点滅」または「点滅」の方法です。NSTimerを使用してこの小さなアニメーションを模倣しようとしていますが、気分が悪くなります。何回点滅しますか?どの時間間隔を使用する必要がありますか?私はたくさんの実験をしました、そしてそれはただ強打から感じます。

誰かが以前にこれを行ったことがありますか、またはメニュー項目にボタンを追加する方法について他の提案がありますか?たぶん、カスタムココアの描画のためだけにスタック交換サイトがあるはずです...

4

3 に答える 3

4

これは1年以上前のことですが、これは私のGoogle検索での最初のヒットであり、回答がありませんでした。そのため、まだ解決策を探している人のために回答を投稿します。

私のアプリでは、NSMenuItemビューのカスタムNSViewでCoreAnimationを使用しました。新しいレイヤーバックビューを作成し、背景色を設定して、カスタムビューに追加しました。次に、レイヤー(点滅している部分)をアニメーション化しました。次に、-(void) animationDidStop:(CAAnimation *)anim finished:(BOOL)flagコールバックで、オーバーレイを削除してメニューを閉じました。これはデフォルトのNSMenuのフラッシュと完全には一致しませんが、37Signals / Stack Overflowイエローフェードテクニックが必要だったので、うまくいきました。ここにそれはコードにあります:

-(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]];
}
于 2012-08-22T19:43:20.407 に答える
2

実際には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向けに開発していない場合は、一見の価値があるかもしれません。

于 2016-11-29T17:00:13.213 に答える
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
}
于 2015-03-10T16:03:01.513 に答える