10

カスタム NSButton を描画しようとしましたが、ここで車輪を再発明しているようです。閉じるボタン、最小化ボタン、ズーム ボタンに使用されるデフォルトの画像を置き換える方法はありますか?

いくつかのアプリはすでにそれを行っています:

  • OSX 10.8 のリマインダー アプリ (ウィンドウが重要でない場合は濃い灰色で表示されますが、ほとんどの場合は明るい灰色で表示されます)
  • Tweetbot (すべてのボタンは完全にカスタムに見えます)

より詳しい情報:

システムのデフォルトをそのまま生成できますstandardWindowButton:NSWindowCloseButton。しかし、そこからsetImageセッターはボタンの外観を変更しません。

4

1 に答える 1

28

編集:私がこれを書いて以来、INAppStoreはこれを行うためのかなり良い方法を実装しましたINWindowButton. ドラッグ アンド ドロップ ソリューションを探している場合は、そこで確認してください。ただし、以下のコードは独自の実装に役立ちます。


そのため、sを変更する方法が見つかりませんでしたstandardWindowButton。ここでは、独自のボタンを作成する方法のウォークスルーを示します。

注:ボタンには 4 つの状態があります。

  • ウィンドウ非アクティブウィンドウ非アクティブ コントロール
  • ウィンドウがアクティブ - 通常ウィンドウ アクティブ法線コントロール
  • ウィンドウがアクティブ - ホバーウィンドウ アクティブ ホバー コントロール
  • ウィンドウがアクティブ - 押すウィンドウ アクティブ プレス コントロール

ウォークスルーへ!

ステップ 1: 既存のボタンを非表示にする

NSButton *windowButton = [self standardWindowButton:NSWindowCloseButton];
[windowButton setHidden:YES];
windowButton = [self standardWindowButton:NSWindowMiniaturizeButton];
[windowButton setHidden:YES];
windowButton = [self standardWindowButton:NSWindowZoomButton];
[windowButton setHidden:YES];

ステップ 2: Interface Builder でビューをセットアップする

ホバーするとすべてのボタンがホバー状態に変わるので、ホバーを取得するにはコンテナー ビューが必要です。

  • 幅 54px x 高さ 16px のコンテナ ビューを作成します。
  • NSButtonコンテナー ビュー内に幅 14 ピクセル x 高さ 16 ピクセルの3 つの Square スタイル を作成します。
  • 間に 6px のギャップができるように、ボタンの間隔を空けます。

ボタンのセットアップ

  • 属性インスペクタで、Image各ボタンのプロパティを window-active-normal イメージに設定します。
  • Alternateimage プロパティを window-active-press イメージに設定します。
  • オフBorderedにします。
  • を に設定TypeMomentary Changeます。
  • ボタンごとに、識別子をclose,minimizeまたはに設定しzoomます (以下では、これを使用して NSButton サブクラスをより単純にする方法を説明します)。

ステップ 3: コンテナー ビューとボタンをサブクラス化する

容器:

新しいファイルを作成し、NSView をサブクラス化します。ここでは、通知センターを使用して、いつホバー状態に切り替える必要があるかをボタンに伝えます。

HMTrafficLightButtonsContainer.m

// Tells the view to pick up the hover event
- (void)viewDidMoveToWindow {
    [self addTrackingRect:[self bounds]
                    owner:self
                 userData:nil
             assumeInside:NO];
}

// When the mouse enters/exits we send out these notifications
- (void)mouseEntered:(NSEvent *)theEvent {
    [[NSNotificationCenter defaultCenter] postNotificationName:@"HMTrafficButtonMouseEnter" object:self];
}
- (void)mouseExited:(NSEvent *)theEvent {
    [[NSNotificationCenter defaultCenter] postNotificationName:@"HMTrafficButtonMouseExit" object:self];        
}

ボタン:

新しいファイルを作成します。今回はサブクラス NSButton です。これはもう少し説明が必要なので、すべてのコードを投稿します。

HMTrafficLightButton.m

@implementation HMTrafficLightButton {
    NSImage *inactive;
    NSImage *active;
    NSImage *hover;
    NSImage *press;
    BOOL activeState;
    BOOL hoverState;
    BOOL pressedState;
}

-(id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {        
        [self setup];
    }
    return self;
}

- (id)initWithFrame:(NSRect)frameRect {
    self = [super initWithFrame:frameRect];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)setup {
    // Setup images, we use the identifier to chose which image to load
    active = [NSImage imageNamed:[NSString stringWithFormat:@"window-button-%@-active",self.identifier]];
    hover = [NSImage imageNamed:[NSString stringWithFormat:@"window-button-%@-hover",self.identifier]];
    press = [NSImage imageNamed:[NSString stringWithFormat:@"window-button-%@-press",self.identifier]];
    inactive = [NSImage imageNamed:@"window-button-all-inactive"];

    // Checks to see if window is active or inactive when the `init` is called
    if ([self.window isMainWindow] && [[NSApplication sharedApplication] isActive]) {
        [self setActiveState];
    } else {
        [self setInactiveState];
    }

    // Watch for hover notifications from the container view
    // Also watches for notifications for when the window
    // becomes/resigns main
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(setActiveState)
                                                 name:NSWindowDidBecomeMainNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(setInactiveState)
                                                 name:NSWindowDidResignMainNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(hoverIn)
                                                 name:@"HMTrafficButtonMouseEnter"
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(hoverOut)
                                                 name:@"HMTrafficButtonMouseExit"
                                               object:nil];
}

- (void)mouseDown:(NSEvent *)theEvent {
    pressedState = YES;
    hoverState = NO;
    [super mouseDown:theEvent];
}

- (void)mouseUp:(NSEvent *)theEvent {
    pressedState = NO;
    hoverState = YES;
    [super mouseUp:theEvent];
}

- (void)setActiveState {
    activeState = YES;
    if (hoverState) {
        [self setImage:hover];
    } else {
        [self setImage:active];
    }
}

- (void)setInactiveState {
    activeState = NO;
    [self setImage:inactive];
}

- (void)hoverIn {
    hoverState = YES;
    [self setImage:hover];
}

- (void)hoverOut {
    hoverState = NO;
    if (activeState) {
        [self setImage:active];
    } else {
        [self setImage:inactive];
    }
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end

IB で、コンテナ ビューのカスタム クラスと 3 つのボタンすべてを、作成したそれぞれのクラスに設定します。

ステップ 4: ボタンのアクションを設定する

standardWindowButtonビュー コントローラから呼び出されるこれらのメソッドは、 s'と同じです。それらを IB のボタンにリンクします。

- (IBAction)clickCloseButton:(id)sender {
    [self.view.window close];
}
- (IBAction)clickMinimizeButton:(id)sender {
    [self.view.window miniaturize:sender];
}
- (IBAction)clickZoomButton:(id)sender {
    [self.view.window zoom:sender];
}

ステップ 5: ビューをウィンドウに追加する

ウィンドウ コントロール専用の別の xib とビュー コントローラーのセットアップがあります。ビュー コントローラは HMWindowControlsController と呼ばれます

(HMWindowControlsController*) windowControlsController = [[HMWindowControlsController alloc] initWithNibName:@"WindowControls" bundle:nil];
NSView *windowControlsView = windowControlsController.view;
// Set the position of the window controls, the x is 7 px, the y will
// depend on your titlebar height.
windowControlsView.frame = NSMakeRect(7.0, 10.0, 54.0, 16.0);
// Add to target view
[targetView addSubview:windowControlsView];

お役に立てれば。これはかなり長い投稿です。私が間違いを犯したり、何かを省略したと思われる場合は、お知らせください。

于 2012-10-02T10:31:59.157 に答える