2011-05-07 17 views
8

Soy consciente de que un shadowPath de un CALayer solo se puede usar con animaciones explícitas, sin embargo, todavía no puedo hacer que esto funcione. Sospecho que no estoy pasando el toValue correctamente, ya que entiendo que esto tiene que ser un id, pero la propiedad toma un CGPathRef. Almacenar esto en un UIBezierPath no parece funcionar. Estoy utilizando el siguiente código de prueba:Animación de la propiedad shadowPath de CALayer

CABasicAnimation *theAnimation = [CABasicAnimation animationWithKeyPath:@"shadowPath"]; 
theAnimation.duration = 3.0; 
theAnimation.toValue = [UIBezierPath bezierPathWithRect:CGRectMake(-10.0, -10.0, 50.0, 50.0)]; 
[self.view.layer addAnimation:theAnimation forKey:@"animateShadowPath"]; 

(estoy usando los valores menos a fin de garantizar la sombra se extiende más allá de un punto de vista que se encuentra en la parte superior de la misma ... la propiedad de la capa masksToBounds se establece en NO) .

¿Cómo se logra la animación de shadowPath?

ACTUALIZACIÓN

Problema casi resuelto. Desafortunadamente, el problema principal fue un error algo descuidado ...

El error que cometí fue agregar la animación a la capa raíz del controlador de vista, en lugar de la capa que había dedicado a la sombra. Además, @ pe8ter tenía razón en que el toValue debe ser un molde CGPathRef a id (obviamente, cuando lo había probado antes todavía no tenía animación debido al error de capa incorrecta). La animación funciona con el siguiente código:

CABasicAnimation *theAnimation = [CABasicAnimation animationWithKeyPath:@"shadowPath"]; 
theAnimation.duration = 3.0; 
theAnimation.toValue = (id)[UIBezierPath bezierPathWithRect:myRect].CGPath; 
[controller.shadowLayer addAnimation:theAnimation forKey:@"shadowPath"]; 

Aprecio que esto fue difícil de detectar en el código de muestra que proporcioné. Sin embargo, afortunadamente todavía puede ser útil para personas en una situación similar.

Sin embargo, cuando intento y añadir la línea

controller.shadowLayer.shadowPath = [UIBezierPath bezierPathWithRect:myRect].CGPath; 

la animación deja de funcionar, y la sombra simplemente salta a la posición final al instante. Los doctores dicen que agreguen la animación con la misma clave que la propiedad modificada para anular la animación implícita creada al establecer el valor de la propiedad, sin embargo, shadowPath no puede generar animaciones implícitas ... entonces, ¿cómo obtengo la nueva propiedad? quedarse después de la animación?

+0

Disculpe que no sirvió de nada. La única alternativa que se me ocurre es usar el delegado de 'CALayer' para establecer la propiedad de forma explícita _after_ animation. Ver [esta publicación] (http://stackoverflow.com/questions/2559812/cabasicanimation-not-changing-its-position-property-after-animation-completes). – pe8ter

+0

@ pe8ter: ¡Tan cerca! Seguí esta gran sugerencia, pero hay un ligero destello del shadowPath original antes de 'animationDidStop:' intercepta la animación y establece el marco. Muy frustrante.Esto podría deberse a que tengo que iterar a través de una pequeña serie de controladores de vista para identificar la capa correcta para cada animación, aunque sospecho que el método delegado se acaba de disparar esa fracción de segundo demasiado tarde, después de que shadowPath ya se haya configurado para su valor original – Stuart

+0

Es difícil decir qué está mal con su código. Me burlé de un pequeño programa de prueba e intenté en ambos sentidos; funcionaron como se esperaba sin artefactos visuales. – pe8ter

Respuesta

7

En primer lugar, no configuró la animación fromValue.

En segundo lugar, está en lo cierto: toValue acepta un CGPathRef, excepto que se debe convertir a id. Hacer algo como esto:

theAnimation.toValue = (id)[UIBezierPath bezierPathWithRect:newRect].CGPath; 

También tendrá que establecer la propiedad shadowPath de la capa de forma explícita si desea que el cambio permanezca después de la animación.

+0

Gracias por la respuesta. No configuré 'fromValue' porque según los documentos es opcional (y estoy animando desde la ruta actual). Enviar a 'id', al tiempo que suprime la advertencia del compilador, todavía no resolvió mi problema. Lo suficientemente cierto acerca de establecer explícitamente la propiedad shadowPath para retener el cambio después de la animación, sin embargo, no veo ninguna animación en primer lugar, así que supongo que el problema debe estar en otra parte. – Stuart

+0

Llegar allí ahora - fue descuidadamente enviando la animación a la capa incorrecta. Sin embargo, tuve problemas para conservar el nuevo valor de shadowPath después de la animación. He actualizado mi pregunta. – Stuart

+1

Es hora de comer un pastel humilde. Tu primera sugerencia de configurar 'fromValue' ha resuelto mi problema. Debo admitir que me parece una sutileza extraña, pero al declarar explícitamente el 'fromValue' como la ruta actual por alguna razón permite que la animación proceda correctamente cuando se establece la propiedad. Ojalá los documentos fueran más claros sobre esto. Gracias por toda tu ayuda. – Stuart

1
let cornerRadious = 10.0 
     // 
     let shadowPathFrom = UIBezierPath(roundedRect: rect1, cornerRadius: cornerRadious) 
     let shadowPathTo = UIBezierPath(roundedRect: rect2, cornerRadius: cornerRadious) 
     // 
     layer.masksToBounds = false 
     layer.shadowColor = UIColor.yellowColor().CGColor 
     layer.shadowOpacity = 0.6 
     // 
     let shadowAnimation = CABasicAnimation(keyPath: "shadowPath") 
     shadowAnimation.fromValue = shadowPathFrom.CGPath 
     shadowAnimation.toValue = shadowPathTo.CGPath 
     shadowAnimation.duration = 0.4 
     shadowAnimation.autoreverses = true 
     shadowAnimation.removedOnCompletion = true 
     shadowAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) 
     layer.addAnimation(shadowAnimation, forKey: "shadowAnimation") 
Cuestiones relacionadas