Editar: Desde que escribí esto, INAppStore ha implementado una forma bastante agradable de hacerlo con INWindowButton
. Si está buscando una solución de arrastrar y soltar, consulte allí, pero el código siguiente aún lo ayudará a implementar el suyo propio.
Así que no pude encontrar una manera de alterar el standardWindowButton
s. Aquí hay un tutorial de cómo creé mis propios botones.
Nota: Hay 4 estados de los botones pueden estar en
- ventana inactiva

- ventana activa - Normal

- ventana activa - ciernen

- ventana activa - pulse

¡En el tutorial!
Paso 1: ocultar los botones preexistentes
NSButton *windowButton = [self standardWindowButton:NSWindowCloseButton];
[windowButton setHidden:YES];
windowButton = [self standardWindowButton:NSWindowMiniaturizeButton];
[windowButton setHidden:YES];
windowButton = [self standardWindowButton:NSWindowZoomButton];
[windowButton setHidden:YES];
Paso 2: Configuración de la vista en el Interface Builder
Usted notará Al pasar por encima de los botones de todo cambio en su vuelo estacionario estado, por lo que necesitamos una vista de contenedor para recoger el vuelo estacionario.
- crear una vista recipiente para ser 54px de ancho x 16px de alto.
- Crea 3 estilo cuadrado
NSButton
s, cada uno de 14px de ancho x 16px alto dentro de la vista del contenedor.
- Coloque los botones de manera que haya espacios de 6px intermedios.
Configuración de los botones
- En el inspector de atributos, establezca la propiedad
Image
para cada botón a la ventana de imagen activa de lo normal.
- Establezca la propiedad de imagen
Alternate
en la imagen de ventana activa-prensa.
- Turn
Bordered
off.
- Establezca
Type
en Momentary Change
.
- Para cada botón establezca el identificador a
close
, minimize
o zoom
(continuación verá cómo se puede utilizar esto para hacer más simple la subclase NSButton)
Paso 3: subclase la vista contenedora & botones
envase:
Crear un nuevo archivo, subclase NSView. Aquí vamos a usar el Centro de notificaciones para indicarles a los botones cuándo deberían cambiar a su estado de desplazamiento.
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];
}
Botones:
Crear un nuevo archivo, esta vez subclase NSButton. Este es un poco más para explicar, así que solo publicaré todo el código.
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
En IB conjunto de la clase personalizada de la vista de contenedor y los 3 botones a sus respectivas clases que acabamos de crear.
Paso 4: Establecer las acciones de los botones
Estos métodos, llamados desde el controlador de vista, son los mismos que el standardWindowButton
s'. Enlázalos a los botones en 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];
}
Paso 5: Añadir la vista a la ventana
Tengo una configuración de controlador de xib y vista separada específicamente para los controles de ventana. El controlador de vista se llama 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];
Espero que esto ayude. Esta es una publicación bastante larga, si crees que cometí un error o dejé algo, por favor avísame.
Esta no es una publicación larga, es una ** excelente ** respuesta. Marcado como referencia futura. – sosborn
@sosborn gracias, agradezco los comentarios :) –
Esta publicación no trata problemas como la accesibilidad y el comportamiento del primer mouse. Estos son difíciles de hacer bien ... ¡lo mejor es usar los botones del sistema! (Tenga en cuenta que a partir de Yosemite, las barras de herramientas y las barras de título de la ventana se pueden combinar y los botones de la ventana se centrarán verticalmente.) – jtbandes