2012-04-30 11 views
14

Estoy tratando de crear una subclase de CALayer con una propiedad personalizada index que puedo animar y cambiar directamente para mostrar una imagen diferente basada en el índice.¿Cómo exactamente subclase CALayer y utiliza una propiedad personalizada?

En la cabecera, que declaró:

@property NSUInteger index; 

En la implementación, que hizo caso omiso de needDisplayForKey:

+ (BOOL)needsDisplayForKey:(NSString *)key 
{ 
    if ([key isEqualToString:@"index"]) 
     return YES; 
    else 
     return [super needsDisplayForKey:key]; 
} 

Ahora, en el método display, quiero mostrar una imagen basada en el índice . Sin embargo, durante una animación, el valor de self.index nunca cambia, así que tengo que consultar el valor de la capa de presentación, contrariamente al ejemplo de Providing CALayer Content by Subclassing:

- (void)display 
{ 
    NSUInteger presentationIndex = [(CustomLayer *)[self presentationLayer] index]; 
    self.contents = (id)[[images objectAtIndex:presentationIndex] CGImage]; 
} 

El problema es, si lo hago, no puedo establezca el valor index directamente fuera de una animación, ya que solo cambiará la capa del modelo, y el método display consulta explícitamente la capa de presentación.

Si añado un método de inicialización que copia el valor de index, funciona:

- (id)initWithLayer:(id)layer 
{ 
    self = [super initWithLayer:layer]; 
    if (self) { 
     if ([layer isKindOfClass:[CustomLayer class]]) 
      self.index = [(CustomLayer *)layer index]; 
    } 
    return self; 
} 

Sin embargo, después o antes de una animación, siempre hay un problema técnico de imagen 1, ya que la presentación o el valor modelo de Don 't coinciden (dependiendo de si establezco index en el valor de destino o no).

  • Sorprendentemente, parece que el método drawInContext: siempre tiene el valor correcto para [self index], pero no es el método que desea utilizar ya que acabo de establecer la propiedad content con una imagen.
  • Tengo diferentes comportamientos según la forma en que implemente la propiedad index. Si uso @dynamic index (que funciona, aunque la documentación no dice que los getters/setters personalizados de propiedad se implementarán dinámicamente), se llama a display cada vez que se cambia el valor de index. Si uso @synthesize o implemente un setter, no se llama a display, por lo que también necesitaría cambiar content en el setter.
  • ¿Debo usar una variable de instancia? ¿Debería usar la implementación dinámica? ¿O debería usar setValue:forKey: en su lugar?

Como puede ver, estoy un poco confundido acerca de cómo obtener el resultado que quiero, y cómo implementar correctamente una subclase de CALayer con una propiedad personalizada. ¡Cualquier ayuda, y explicaciones, serían apreciadas!

+2

"La documentación no dice que captadores de propiedad personalizada/set se aplicarían de forma dinámica" - en realidad, esto es * * documentado en 'CALayer.h':" CALayer implementa el protocolo estándar NSKeyValueCoding para todas las propiedades de Objective C definidas por la clase y sus subclases. Implementa dinámicamente los métodos de acceso faltantes para las propiedades declaradas por subclases ". Por lo tanto, desea utilizar '@ dynamic' si desea' 'needsDisplayForKey:' para que funcione. –

+2

Una gran pregunta ... Estas preguntas "fundamentales" no están suficientemente explicadas en los documentos, y son demasiado esotéricas para todo-pero-la-mayoría-implicada de cómo hacerlo. 'Los de CALayer son tan raros ... Creo que Apple lamenta su implementación de ellos, o tiene demasiadas tecnologías en competencia para molestarse en documentar realmente sus comportamientos a menudo misteriosos. –

+3

Estoy de acuerdo ... Core Animation es trivial de usar para tareas básicas, pero si intentas profundizar, se vuelve esotérico. Como el hecho de que las capas tienen tiempo, además del tiempo de animación. O la misteriosa propiedad 'contents' cuyo tipo es' id', y que puede contener un 'CABackingStore' en caché. O el hecho de que 'CATransition' hereda de' CAAnimation' aún funciona de una manera completamente opaca ... O incluso la relación entre 'UIView' animation blocks y' CALayer' animation ... – Guillaume

Respuesta

11

Hay un excelente tutorial en la web que explica cómo crear una subclase CALayer personalizada con propiedades animables. No he tenido ocasión de probarlo todavía, pero lo he marcado como favorito. Aquí está el enlace:

Animating Pie Slices Using a Custom CALayer

Parece que los principales trucos son:

Uso @dynamic, no @synthesize de las propiedades animables de su encargo CALayer.

Anulación actionForKey :, initWithLayer :, y needsDisplayForKey :, y quizás drawInContext:

+0

Este ejemplo usa su propia rutina de dibujo CoreGraphics en 'drawInContext:', que como dije, siempre tiene el valor correcto para la propiedad animada. Sin embargo, en el método 'display', solo el valor presentado es correcto. La solución que finalmente utilicé para obtener el resultado que quería es sintetizar la propiedad y llamar manualmente a 'setNeedsDisplay' cuando quiero mostrar un cambio en la propiedad fuera de una animación. – Guillaume

+0

Gracioso ... Lo había visto, y en realidad todo funcionaba ... para una Mac, incluso. Intentaré y publicaré las clases trabajadoras. –

Cuestiones relacionadas