2010-05-23 7 views
14

Supongo que tengo que convertir el CGRect en un objeto para pasarlo deValue?Cómo animar el marco de una capa con CABasicAnimation?

Esta es la forma en que lo intento, pero no funciona:

CABasicAnimation *frameAnimation = [CABasicAnimation animationWithKeyPath:@"frame"]; 
frameAnimation.duration = 2.5; 
frameAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 
frameAnimation.fromValue = [NSValue valueWithCGRect:myLayer.frame]; 
frameAnimation.toValue = [NSValue valueWithCGRect:theNewFrameRect]; 
[myLayer addAnimation:frameAnimation forKey:@"MLC"]; 

Respuesta

-6

Creo que se necesita para cambiar su última línea para que funcione:

[myLayer addAnimation:frameAnimation forKey:@"frame"]; 

También puede establecer una acción a la capa para hacer todos los cambios de marco animados con su animación:

CABasicAnimation *frameAnimation = [CABasicAnimation animation]; 
frameAnimation.duration = 2.5; 
frameAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 

myLayer.actions = [NSDictionary dictionaryWithObjectsAndKeys:frameAnimation, @"frame", nil]; 

En CALayer deReferencia de métodopuede encontrar cómo la capa busca las acciones para animar sus propiedades.

+1

Gracias Vladimir. He descubierto que CALayer no puede animar la propiedad del marco directamente. La documentación dice eso en un cuadro gris. No lo he visto por alguna razón. – dontWatchMyProfile

+6

La última línea está bien tal como está: la clave que especifique en addAnimation puede ser una NSString arbitraria. Creo que la respuesta real es la de berilio por debajo de – Mattia

+0

'[myLayer addAnimation: frameAnimation forKey: @" frame "];' 'frame' es solo un nombre para la animación y no tiene nada que ver con la propiedad real que se está animando ... –

82

La propiedad de marco de un CALayer es una propiedad derivada, que depende de la posición, punto de anclaje, límites y transformación de la capa. En lugar de animar el marco, en su lugar debe animar la posición o los límites, según el efecto que intente lograr.

Para mover una capa, puede animar la position:

-(void)moveLayer:(CALayer*)layer to:(CGPoint)point 
{ 
    // Prepare the animation from the current position to the new position 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; 
    animation.fromValue = [layer valueForKey:@"position"]; 

    // NSValue/+valueWithPoint:(NSPoint)point is available on Mac OS X 
    // NSValue/+valueWithCGPoint:(CGPoint)point is available on iOS 
    // comment/uncomment the corresponding lines depending on which platform you're targeting 

    // Mac OS X 
    animation.toValue = [NSValue valueWithPoint:NSPointFromCGPoint(point)]; 
    // iOS 
    //animation.toValue = [NSValue valueWithCGPoint:point]; 

    // Update the layer's position so that the layer doesn't snap back when the animation completes. 
    layer.position = point; 

    // Add the animation, overriding the implicit animation. 
    [layer addAnimation:animation forKey:@"position"]; 
} 

Para cambiar el tamaño de una capa, que sería animar la bounds parámetro:

-(void)resizeLayer:(CALayer*)layer to:(CGSize)size 
{ 
    // Prepare the animation from the old size to the new size 
    CGRect oldBounds = layer.bounds; 
    CGRect newBounds = oldBounds; 
    newBounds.size = size; 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"bounds"]; 

    // NSValue/+valueWithRect:(NSRect)rect is available on Mac OS X 
    // NSValue/+valueWithCGRect:(CGRect)rect is available on iOS 
    // comment/uncomment the corresponding lines depending on which platform you're targeting 

    // Mac OS X 
    animation.fromValue = [NSValue valueWithRect:NSRectFromCGRect(oldBounds)]; 
    animation.toValue = [NSValue valueWithRect:NSRectFromCGRect(newBounds)]; 
    // iOS 
    //animation.fromValue = [NSValue valueWithCGRect:oldBounds]; 
    //animation.toValue = [NSValue valueWithCGRect:newBounds]; 

    // Update the layer's bounds so the layer doesn't snap back when the animation completes. 
    layer.bounds = newBounds; 

    // Add the animation, overriding the implicit animation. 
    [layer addAnimation:animation forKey:@"bounds"]; 
} 

se pueden combinar estas animaciones usando un CAAnimationGroup si necesita mover y cambiar el tamaño de una capa al mismo tiempo.

+0

¡Gracias por proporcionar ese enlace extremadamente útil! – RonLugge

+0

Fui arrojado por la respuesta aceptada. ¡Gracias! –

+3

Esta debería ser la respuesta aceptada. – CodeReaper

6

podemos cambiar las propiedades de los "límites" y "posición" para animar que, como

-(void)handleTap2:(UITapGestureRecognizer *)recognizer { 

    UIImageView *vw = (UIImageView *)[recognizer view]; 

    CGPoint startPoint = CGPointMake(vw.frame.size.width/2+vw.frame.origin.x, vw.frame.size.height/2+vw.frame.origin.y); 
    CGPoint endPoint = CGPointMake(160, 240); 

    CGRect startBounds = vw.bounds; 
    CGRect stopBounds = self.view.bounds; 

    layer = [CALayer layer]; 
    layer.frame = self.view.frame; 
    layer.contents = (id)[vw.image CGImage]; 

    [self.view.window.layer addSublayer:layer]; 

    CABasicAnimation * baseAnimation = [CABasicAnimation animationWithKeyPath:@"position"]; 

    baseAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 
    baseAnimation.fromValue = [NSValue valueWithCGPoint:startPoint] ; 
    baseAnimation.toValue = [NSValue valueWithCGPoint:endPoint] ; 

    CABasicAnimation * boundsAnimation = [CABasicAnimation animationWithKeyPath:@"bounds"]; 

    boundsAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 
    boundsAnimation.fromValue = [NSValue valueWithCGRect:startBounds] ; boundsAnimation.toValue = [NSValue valueWithCGRect:stopBounds] ; 

    CAAnimationGroup * group =[CAAnimationGroup animation]; 
    group.removedOnCompletion=NO; group.fillMode=kCAFillModeForwards; 
    group.animations =[NSArray arrayWithObjects:baseAnimation, boundsAnimation, nil];  
    group.duration = 0.7; 

    [layer addAnimation:group forKey:@"frame"]; 
} 
3

La pregunta es antiguo, pero lo voy a hacer de todos modos.

La propiedad de marco no es animable. Tienes que animar otras propiedades. También debes desactivar las animaciones implícitas.

let updatedBounds = ... 
    let animation = CABasicAnimation(keyPath: "bounds") 
    animation.duration = 0.5 
    //it's better to start animation from presentation layer in case there is already animation going on 
    animation.fromValue = customLayer.presentation()?.bounds 
    animation.toValue = updatedBounds 
    customLayer.add(animation, forKey: nil) 

    //disable implicit animation for thoose properties 
    CATransaction.begin() 
    CATransaction.setDisableActions(true) 
    //update properties so they will be updated at the end of animation 
    customLayer.bounds = updatedBounds 
    customLayer.position = originalRect.origin 
    customLayer.anchorPoint = CGPoint(x: 0, y: 0) 
    CATransaction.commit() 
1

Aquí hay un ejemplo simple, totalmente funcional, que puede ayudar a alguien.

Simplemente llame al .slideUp() en la clase y se deslizará hacia arriba.

class Slidey: YourViewClass { 

    func slideUp() { 

     print("\n\n SLIDE") 

     let FF = layer.position 
     var TT = FF 
     TT.y -= 100 
     print(FF) 
     print(TT) 

     CATransaction.begin() 
     CATransaction.setDisableActions(true) 

     CATransaction.setCompletionBlock{ [weak self] in 

      print("DONE") 
     } 

     let a = CABasicAnimation(keyPath: "position") 

     a.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) 

     a.isCumulative = false 
     a.autoreverses = false 
     a.isRemovedOnCompletion = true 
     a.repeatCount = 0 
     a.fromValue = FF 
     a.toValue = TT 
     a.duration = 0.70 
     layer.add(a, forKey: nil) 

     CATransaction.commit() 
    } 
} 
Cuestiones relacionadas