2012-02-21 23 views
5

Estoy haciendo un objeto NSView personalizado que tiene un contenido que cambia a menudo, y algunos que cambian con mucha menos frecuencia. Como resultaría, las partes que cambian con menor frecuencia toman más tiempo para dibujar. Lo que me gustaría hacer es renderizar estas dos partes en diferentes capas, de modo que pueda actualizar una u otra por separado, ahorrándole a mi usuario una interfaz de usuario lenta.¿Puedo usar CALayer para acelerar la visualización?

¿Cómo puedo hacer esto? No he encontrado muchos buenos tutoriales sobre este tipo de cosas, y ninguno habla de renderizar NSBezierPaths en un CALayer. ¿Ideas a alguien?

Respuesta

4

Su corazonada es correcta, esta es en realidad una excelente manera de optimizar el dibujo. Lo hice yo mismo, donde tenía algunos fondos estáticos grandes que quería evitar volver a dibujar cuando los elementos se movían hacia arriba.

Todo lo que necesita hacer es agregar CALayer objetos para cada uno de los elementos de contenido en su vista. Para dibujar las capas, debe establecer su vista como delegado para cada capa y luego implementar el método drawLayer:inContext:.

En ese método que acaba de dibujar el contenido de cada capa:

- (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)ctx 
{ 
    if(layer == yourBackgroundLayer) 
    { 
     //draw your background content in the context 
     //you can either use Quartz drawing directly in the CGContextRef, 
     //or if you want to use the Cocoa drawing objects you can do this: 
     NSGraphicsContext* drawingContext = [NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:YES]; 
     NSGraphicsContext* previousContext = [NSGraphicsContext currentContext]; 
     [NSGraphicsContext setCurrentContext:drawingContext]; 
     [NSGraphicsContext saveGraphicsState]; 
     //draw some stuff with NSBezierPath etc 
     [NSGraphicsContext restoreGraphicsState]; 
     [NSGraphicsContext setCurrentContext:previousContext]; 
    } 
    else if (layer == someOtherLayer) 
    { 
     //draw other layer 
    } 
    //etc etc 
} 

Cuando se desea actualizar el contenido de una de las capas, simplemente llame [yourLayer setNeedsDisplay]. Esto llamará al método de delegado anterior para proporcionar el contenido actualizado de la capa.

Tenga en cuenta que, por defecto, cuando se cambia el contenido de la capa, Core Animation proporciona una agradable transición de fundido para el nuevo contenido. Sin embargo, si maneja el dibujo usted mismo probablemente no lo desee, para evitar el fundido predeterminado en la animación cuando cambia el contenido de la capa, también debe implementar el método de delegado actionForLayer:forKey: y evitar la animación devolviendo un acción nula:

- (id<CAAction>)actionForLayer:(CALayer*)layer forKey:(NSString*)key 
{ 
    if(layer == someLayer) 
    { 
     //we don't want to animate new content in and out 
     if([key isEqualToString:@"contents"]) 
     { 
      return (id<CAAction>)[NSNull null]; 
     } 
    } 
    //the default action for everything else 
    return nil; 
} 
+0

Gracias, esto es muy útil. Sin embargo, tengo problemas para activar el método delegado. Estoy configurando mi punto de vista como el delegado y estoy agregando las capas como subcapas de la capa raíz, y estoy llamando 'setNeedsDisplay' pero' drawLayer: inContext' nunca se llama. ¿Algunas ideas? – mtmurdock

+0

¿Puedes publicar tu código? Esto debería funcionar. –

+0

También estoy anulando 'drawRect:' podría estar causando que no llame a la otra función? – mtmurdock

Cuestiones relacionadas