首发于公众号微信
在 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]
]];
}
复制代码
看一下效果,和微信对比一下,是否是一摸同样了:
全文完,感谢阅读 ^_^