自定义 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]
                                   ]];
}
复制代码

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

全文完,感谢阅读 ^_^

相关文章
相关标签/搜索