我已经尝试绘制自定义 NSButton,但似乎我在这里重新发明了轮子。有没有办法只替换用于关闭、最小化和缩放按钮的默认图像?
几个应用程序已经这样做了:
- OSX 10.8 的提醒应用程序(当窗口不是关键时,它们显示为深灰色,而大多数显示为浅灰色)
- Tweetbot(所有按钮看起来完全自定义)
更多信息:
我可以像这样生成系统默认值standardWindowButton:NSWindowCloseButton
。但是从那里setImage
设置器不会改变按钮的外观。
我已经尝试绘制自定义 NSButton,但似乎我在这里重新发明了轮子。有没有办法只替换用于关闭、最小化和缩放按钮的默认图像?
几个应用程序已经这样做了:
更多信息:
我可以像这样生成系统默认值standardWindowButton:NSWindowCloseButton
。但是从那里setImage
设置器不会改变按钮的外观。
编辑:自从我写了这个,INAppStore已经实现了一个非常好的方法来做到这一点INWindowButton
。如果您正在寻找拖放解决方案,请检查那里,但下面的代码仍将帮助您实现自己的。
所以我找不到改变standardWindowButton
s的方法。这是我如何创建自己的按钮的演练。
注意:按钮可以处于 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 中设置视图
你会注意到在悬停时按钮都变成了悬停状态,所以我们需要一个容器视图来接收悬停。
NSButton
在容器视图内创建 3 个 Square 样式,每个 14px 宽 x 16px 高。设置按钮
Image
每个按钮的属性设置为 window-active-normal 图像。Alternate
image 属性设置为 window-active-press 图像。Bordered
。Type
为Momentary 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];
希望这可以帮助。这是一个相当长的帖子,如果您认为我犯了错误或遗漏了什么,请告诉我。