自定義 NSWindow 的交通燈位置

首發於公衆號微信

在 macOS 系統下,App 左上角的 3 個控制按鈕被稱爲「交通燈」,由於他們的顏色和現實中的交通訊號燈同樣(紅(關閉),黃(最小化),綠(最大化))。佈局

實際開發中會遇到按鈕的默認位置不能知足設計的需求,須要調整它們的位置。ui

然而系統並無提供方法直接調整他們的位置,開發中經常使用的方法有兩種:spa

模仿系統按鈕 使用黑魔法更改按鈕位置設計

第一種方法,要模仿系統的行爲須要一些額外的工做量,不考慮。 第二種方法工做量比較小,只是須要作一些分析工做,just do it !3d

查看一下這幾個按鈕的佈局:code

能夠看到它們處於 NSTitlebarContainerView 中的 NSTitlebarView 裏,並且使用的是自動佈局(autolayout)的方式。cdn

這樣思路就很簡單了,只要給這幾個按鈕設置約束,就能夠達到更改位置的目的了。blog

在什麼時機設置約束比較好呢?答案是在 Window 初始化完成以後就是最佳時機,代碼以下:繼承

@implementation TUINSWindow

- (instancetype)initWithContentRect:(CGRect)rect {
...
  [self relayoutWindowButtons];
...
}

- (void)relayoutWindowButtons {
    NSButton *closeButton = [self standardWindowButton:NSWindowCloseButton];
    NSButton *minButton = [self standardWindowButton:NSWindowMiniaturizeButton];
    NSButton *zoomButton = [self standardWindowButton:NSWindowZoomButton];

    NSView *titlebarView = closeButton.superview;
    closeButton.translatesAutoresizingMaskIntoConstraints = NO;
    [titlebarView addConstraints:@[
                                   [NSLayoutConstraint constraintWithItem:closeButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:titlebarView attribute:NSLayoutAttributeTop multiplier:1 constant:9],
                                   [NSLayoutConstraint constraintWithItem:closeButton attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:titlebarView attribute:NSLayoutAttributeLeft multiplier:1 constant:2]
                                   ]];

    minButton.translatesAutoresizingMaskIntoConstraints = NO;
    [titlebarView addConstraints:@[
                                   [NSLayoutConstraint constraintWithItem:minButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:titlebarView attribute:NSLayoutAttributeTop multiplier:1 constant:9],
                                   [NSLayoutConstraint constraintWithItem:minButton attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:titlebarView attribute:NSLayoutAttributeLeft multiplier:1 constant:20]
                                   ]];

    zoomButton.translatesAutoresizingMaskIntoConstraints = NO;
    [titlebarView addConstraints:@[
                                   [NSLayoutConstraint constraintWithItem:zoomButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:titlebarView attribute:NSLayoutAttributeTop multiplier:1 constant:9],
                                   [NSLayoutConstraint constraintWithItem:zoomButton attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:titlebarView attribute:NSLayoutAttributeLeft multiplier:1 constant:38]
                                   ]];
}

@end
複製代碼

TUINSWindow 繼承自 NSWindow,在設置好了 style 以後就能夠調用 relayoutWindowButtons 方法設置約束了。

NSWindow 提供了獲取系統按鈕的方法:- (NSButton *)standardWindowButton:(NSWindowButton)b; 根據以前的分析,按鈕的父窗口就是 NSTitlebarView。

看一下調整以後的效果:

大功告成!

偷偷的說,我發現微信、企業微信的 macOS 版本,它們也是這麼實現的。

若是要像微信 macOS 版本那樣,只須要調整約束以下,在上面的約束中,不添加左約束就能夠了:

- (void)relayoutWindowButtons {
    NSButton *closeButton = [self standardWindowButton:NSWindowCloseButton];
    NSButton *minButton = [self standardWindowButton:NSWindowMiniaturizeButton];
    NSButton *zoomButton = [self standardWindowButton:NSWindowZoomButton];

    NSView *titlebarView = closeButton.superview;
    closeButton.translatesAutoresizingMaskIntoConstraints = NO;
    [titlebarView addConstraints:@[
                                   [NSLayoutConstraint constraintWithItem:closeButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:titlebarView attribute:NSLayoutAttributeTop multiplier:1 constant:9]
                                   ]];

    minButton.translatesAutoresizingMaskIntoConstraints = NO;
    [titlebarView addConstraints:@[
                                   [NSLayoutConstraint constraintWithItem:minButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:titlebarView attribute:NSLayoutAttributeTop multiplier:1 constant:9]
                                   ]];

    zoomButton.translatesAutoresizingMaskIntoConstraints = NO;
    [titlebarView addConstraints:@[
                                   [NSLayoutConstraint constraintWithItem:zoomButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:titlebarView attribute:NSLayoutAttributeTop multiplier:1 constant:9]
                                   ]];
}
複製代碼

看一下效果,和微信對比一下,是否是一摸同樣了:

全文完,感謝閱讀 ^_^

相關文章
相關標籤/搜索