macos - v10 - versiones de mac os capitan
Problemas para hacer coincidir el fondo vibrante de un Yosemite NSMenuItem que contiene una vista personalizada (5)
Estoy intentando agregar una vista personalizada a un NSMenuItem en la barra de menú de OS X 10.10 Yosemite.
La vista personalizada es simplemente un fondo NSView con una “etiqueta” NSTextField.
El problema es que el NSView de fondo recibe una vibración / transparencia de estilo Yosemite cuando se agrega al menú. La etiqueta NSTextfield no lo es.
A través del uso de NSRectFillUsingOperation
que se vea bien para algunos colores de fondo en Yosemite. Pero otros siguen sin coincidir. Cuando está funcionando, después de "resaltar" manualmente la vista, los colores originales cambian y ya no coinciden. Puedo desenterrar algún código de ejemplo para esto si es necesario.
Entonces, cuando se ve algo bueno en Yosemite, se ve terrible en 10.9 Mavericks.
También he intentado establecer la propiedad wantsLayer
en YES para convertir la vista en una vista respaldada por CALayer. Esto crea otros problemas, como el texto que no es anti-aliasing correctamente sobre un fondo claro.
Mi pregunta:
¿Cómo muestro una etiqueta en la parte superior de una vista personalizada de NSMenuItem? El fondo de la etiqueta debe coincidir exactamente con el fondo de la vista. La solución debe funcionar en Yosemite y Mavericks.
Código de ejemplo a continuación:
self.statusItem = [[NSStatusBar systemStatusBar]
statusItemWithLength:NSVariableStatusItemLength];
[self.statusItem setTitle:@"TEST"];
[self.statusItem setHighlightMode:YES];
[self.statusItem setEnabled:YES];
[self.statusItem setTarget:self];
NSMenu *menu = [[NSMenu alloc] init];
[menu addItemWithTitle:@"Disabled menu item" action:nil keyEquivalent:@""];
[menu addItemWithTitle:@"Enabled menu item" action:@selector(enabled) keyEquivalent:@""];
NSTextField *label = [[NSTextField alloc] initWithFrame:NSMakeRect(30, 20, 50, 20)];
label.stringValue = @"label";
label.editable = NO;
label.bordered = NO;
label.backgroundColor = [NSColor blueColor];
//label.backgroundColor = [NSColor clearColor];
PKMenuItemView *view = [[PKMenuItemView alloc] initWithFrame:NSMakeRect(0, 0, 200, 50)];
[view addSubview:label];
NSMenuItem *viewMenuItem = [[NSMenuItem alloc] init];
[viewMenuItem setView:view];
[menu addItem:viewMenuItem];
self.statusItem.menu = menu;
He subclasificado el NSView para reemplazar drawRect:
y dibujar un fondo de color:
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
[[NSColor blueColor] setFill];
NSRectFill(dirtyRect);
//NSRectFillUsingOperation(dirtyRect, NSCompositeSourceOver);
}
Acabo de descubrir que +[NSColor keyboardFocusIndicatorColor]
es el color correcto (al menos en El Capitán), mientras que el esperado +[NSColor keyboardFocusIndicatorColor]
selectedMenuItemColor
es muy oscuro.
Creo que tengo menos solución "hackish". De hecho, es causada por el nuevo NSVisualEffectView y Vibrancy en Yosemite. Aprendí que hay reglas bastante complejas sobre cómo se dibujan las vistas cuando son subvistas de NSVisualEffectView. Se discutió en la WWDC 2014 en la sesión 220: adopción de funciones avanzadas de la nueva interfaz de usuario de OS X Yosemite . Te recomiendo que veas este video de sesión para obtener una explicación completa.
En breve, parece que su problema puede deberse a los colores que usa. Hay dos nuevos colores de sistema: [NSColor labelColor]
y [NSColor secondaryLabelColor]
. Estos dos se ajustan automáticamente cuando se dibujan dentro de NSVisualEffectView. Además, su vista personalizada debe ser compatible con el efecto Vibrancy. Esto se hace anulando - (BOOL)allowsVibrancy
método de - (BOOL)allowsVibrancy
y devolviendo SÍ.
Consulte el video de la sesión que se menciona arriba o descargue las diapositivas de la sesión en PDF para obtener información precisa. Esto se discute en la diapositiva 124 en PDF y cerca de la mitad del video.
Desafortunadamente hay actualmente varios problemas en Yosemite. Como Matthes ya mencionó, puedes usar labelColor()
y secondaryLabelColor()
. El uso de esos colores no hace que la etiqueta dibuje el fondo extraño que está viendo.
Sin embargo, labelColor()
solo funciona bien para VibrantDark porque allí el color de la etiqueta es blanco cuando se resalta un NSMenuItem y cuando no está resaltado. Con VibrantLight, labelColor
es negro y, por lo tanto, es muy difícil de leer en la parte superior del resaltado azul.
Para el color de resaltado de la vista personalizada de su NSMenuItem, uno podría pensar que debería usar el menúMenuItemColor selectedMenuItemColor()
dado su nombre. El problema con esto es que el color no coincide realmente con el color de resalte del menú que se ve en NSMenuItems sin una vista personalizada. El color es completamente incorrecto tanto para VibrantLight como para VibrantDark.
Tl; dr: Entonces, ¿cómo puede crear un NSMenuItem personalizado que use exactamente el mismo color de texto y color de resaltado? Usted no puede Debería usar labelColor()
y selectedMenuItemColor()
pero el primero solo funciona correctamente para VibrantDark, y el último no coincide en absoluto.
Realmente espero estar equivocado porque estoy tratando de lograr lo mismo :(
Edición: Here hay un proyecto de ejemplo si la gente quiere echar un vistazo.
Respuesta de un ticket de soporte técnico para desarrolladores de Apple que abrí en 2015:
Re: DTS Auto-Ack - Fondo vibrante y resaltado de vista personalizada NSMenuItems
Este es un problema difícil de abordar, especialmente dado que el dibujo de selección de menú no fue diseñado para elementos de menú con vistas personalizadas, y el dibujo de selección de menú (colores, etc.) puede cambiar en el futuro. Por esta razón, le pedimos que presente informes de errores para que la selección del menú se admita con vistas personalizadas, si se solicita, para que los cambios futuros en OS X no requieran que los desarrolladores mantengan continuamente su código para coincidir con las apariencias de color futuras.
El "Menú de aplicaciones y temas de programación de la lista emergente" dice esto:
Vistas en los elementos del menú -
“Un elemento de menú con una vista no dibuja su título, estado, fuente u otros atributos de dibujo estándar, y asigna la responsabilidad del dibujo por completo a la vista. Los equivalentes de teclado y la selección de tipo continúan usando la tecla equivalente y el título como de costumbre ".
Dado que todo el dibujo depende del desarrollador, las vistas personalizadas en los elementos del menú no deben dibujarse como "seleccionadas".
Las API para obtener el color de selección correcto obviamente no hacen lo que se supone que deben hacer, de ahí la solicitud de presentar un informe de error. Ojalá pudiéramos ofrecer soluciones más concretas al problema, pero una solución que se ofrece hoy puede no demorarse mañana y no queremos sentar un mal precedente en soluciones que sean riesgosas. Las aplicaciones de Apple tienen acceso a API privadas de nivel inferior que logran sus resultados. No podemos ofrecerle estas soluciones ya que son privadas.
Si selectedMenuItemColor () no hace coincidir el color de resaltado del menú con Vibrante claro y oscuro, es un error que se debe archivar y corregir.
Por último, Apple recomienda utilizar las API de NSMenuItem tanto como sea posible para lograr lo que desea en los menús. Es probable que las capturas de pantalla que incluyó se puedan realizar sin aplicar vistas personalizadas.
Seguramente es un poco hack, pero funcionó para mí. Intente agregar un NSImageView con una imagen vacía a su vista personalizada. La vista de la imagen debe ocupar toda la vista.