2010-03-07 10 views
30

Tengo una subclase CALayer, MyLayer, que tiene una propiedad NSInteger llamada myInt. Realmente me gustaría animar esta propiedad a través de CABasicAnimation, pero parece que CABasicAnimation solo funciona en las propiedades llamadas "animables" (límites, posición, etc.). ¿Hay algo que pueda anular para hacer que mi propiedad myInt personalizada sea animable?Animar una propiedad personalizada de la subclase CALayer

+1

¿Intentas hacer que la propiedad sea un "flotador"? – kennytm

Respuesta

68

Sí, es posible (solo en las últimas versiones de Core Animation, creo, es decir, iPhone 3.0+ y OS X 10.6+).

  1. Haga su propiedad dinámica para que CA implementa los descriptores de acceso para usted:

    @dynamic myInt; 
    
  2. Envía la capa que los cambios de la propiedad requieren volver a dibujar:

    + (BOOL)needsDisplayForKey:(NSString*)key { 
        if ([key isEqualToString:@"myInt"]) { 
         return YES; 
        } else { 
         return [super needsDisplayForKey:key]; 
        } 
    } 
    
  3. Usar el valor de myInt en su método drawInContext:. Ahora, cuando anime myInt, Core Animation interpolará los valores para cada paso de la animación y repetidamente le pedirá a la capa que dibuje.

  4. Si también desea habilitar las animaciones implícitas para esta propiedad, también anule actionForKey:.

+0

¡Gracias! ¡Esto me tiene tan cerca de una solución que puedo probarla! -drawInContext: se llama varias veces con myInt interpolado correctamente. Desafortunadamente, CGContextDrawImage() ya no funciona mientras la animación se está ejecutando. Los rectos que llené o los trazos que acaricio se dibujaron correctamente, pero la imagen que normalmente dibuja CGContextDrawImage() simplemente desaparece hasta que la animación termina como si nunca se llamara a CGContextDrawImage(). Estoy desconcertado. ¿Alguna idea? – jemmons

+0

No tengo idea, lo siento. Espero que encuentres una solución. –

+3

Eso está bien. Tu respuesta sigue siendo una de las mejores respuestas escritas que he visto en Stack Overflow :) – jemmons

6

Hay es una manera de conservar los Ivars de sus subclases CALayer personalizados. Sobreescribe initWithLayer :, el método que se llama para crear una copia de capas personalizadas. Por ejemplo, si tiene una capa en la que desea crear una propiedad personalizada denominada 'ángulo', podría utilizar el siguiente código:

@implementation AngledLayer 
@synthesize angle = _angle 

// Tell Core Animation that this key should be animated 
+ (BOOL) needsDisplayForKey:(NSString *)key 
{ 
    if ([key isEqualToString:@"angle"]) return YES; 
    return [super needsDisplayForKey:key]; 
} 


// Make sure that, when the layer is copied, so is the custom ivar 
- (id) initWithLayer:(id)layer 
{ 
    self = [super initWithLayer:layer]; 
    if (self) { 
     AngledLayer *angledVersion = (AngledLayer *)layer; 
     self.angle = angledVersion.angle; 
    } 
    return self; 
} 

Y de tu tío Bob! Tenga en cuenta que no puede usar este objeto con animación implícita, para lo cual también debería reemplazar el método actionForKey :.

+1

Esto no funciona para mí. Dentro de 'initWithLayer', la capa siempre tiene el valor inicial de la propiedad, incluso mientras se anima. El colocador es llamado a otro lugar. – zakdances

+1

Estoy viendo lo mismo que yourfriendzak. Si bien la combinación de initWithLayer y needsDisplayForkey permite que la animación suceda, tan pronto como finaliza, la capa vuelve a su valor inicial. Todavía estoy buscando una solución. –

+0

De acuerdo, parece que no me di cuenta de que @dynamic causa que el colocador se anime automáticamente. Pero si por alguna razón necesitas hacer más, probablemente necesites crear tu propio setter que tenga su propio bloque de animación para que puedas cambiar la propiedad de la capa antes de que la animación tenga lugar. Ver [enlace] (http://stackoverflow.com/questions/11515647/objective-c-cabasicanimation-applying-changes-after-animation) –

Cuestiones relacionadas