2010-05-23 12 views
14

Chyba muszę przekonwertować CGRect na obiekt i przekazać go do fromValue?Jak animować klatkę warstwy za pomocą CABasicAnimation?

ten sposób staram, ale to nie działa:

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"]; 

Odpowiedz

-6

Chyba trzeba zmienić swój ostatni wiersz, aby to działało:

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

Można również ustawić działanie na warstwę, aby wszystkie zmiany klatek animowane z animacji:

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

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

W CALayer na actionForKey: odwołanie do metody można znaleźć sposób wyszukiwania warstwy dla działań animowanych jej właściwości.

+1

Dzięki Vladimir. Odkryłem, że CALayer nie może bezpośrednio animować właściwości ramki. Dokumentacja mówi, że w szarym polu. Nie widziałem tego z jakiegoś powodu. – dontWatchMyProfile

+6

Ostatnia linia jest w porządku, ponieważ jest - kluczem określonym w addAnimation może być arbitralny NSString. Myślę, że właściwą odpowiedzią jest beryl poniżej – Mattia

+0

'[myLayer addAnimation: frameAnimation forKey: @" frame "];' 'frame' jest po prostu nazwą dla animacji i nie ma nic wspólnego z faktyczną animowaną właściwością ... –

82

Właściwość frame obiektu CALayer jest właściwością pochodną, ​​zależną od położenia, anchorPoint, granic i transformacji warstwy. Zamiast animować klatkę, należy zamiast tego animować położenie lub granice, w zależności od tego, jaki efekt chcesz osiągnąć.

Aby przenieść warstwę można animować 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"]; 
} 

Aby zmienić warstwę, byś animować parametr bounds:

-(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"]; 
} 

Można łączyć te animacje za pomocą CAAnimationGroup if musisz przesuwać i zmieniać rozmiar warstwy w tym samym czasie.

+0

Dziękujemy za udostępnienie tego niezwykle pomocnego linku! – RonLugge

+0

Zostałem odrzucony przez zaakceptowaną odpowiedź. Dziękuję Ci! –

+3

To powinna być zaakceptowana odpowiedź. – CodeReaper

6

możemy zmienić właściwości „więzów” i „pozycji”, aby ją animować, takich jak

-(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

Pytanie jest antyk, ale będę go odebrać i tak.

Właściwość ramki nie jest animatable. Musisz animować inne właściwości. Musisz również wyłączyć niejawne animacje.

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

Oto prosty, w pełni działający przykład, który może pomóc komuś.

Po prostu zadzwoń pod numer .slideUp(), a zostanie on przesunięty w górę.

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() 
    } 
} 
Powiązane problemy