如何用CABasicAnimation动画化图层的框架?

问题描述:

我想我必须将CGRect转换为一个对象以将它传递给fromValue?如何用CABasicAnimation动画化图层的框架?

这是我的尝试,但它不工作:

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

我猜你需要改变你的最后一行,使其工作:

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

您也可以设置该层的作用,使你的动画动画所有帧之间的变化:

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

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

在的CALayer的actionForKey:方法参考,您可以找到图层如何查找动画来对其属性进行动画处理。

+1

谢谢弗拉基米尔。我发现CALayer不能直接为框架属性设置动画。文档说明在灰色框中。由于某种原因没有看到它。 – dontWatchMyProfile 2010-05-23 19:18:31

+6

最后一行没问题 - 你在addAnimation中指定的键值可以是任意的NSString。我认为实际的答案是铍的低于 – Mattia 2012-01-24 20:52:56

+0

'[myLayer addAnimation:frameAnimation forKey:@“frame”];''frame'只是一个动画的名称,并且与实际的动画无关...... – 2015-11-16 09:53:23

CALayer的frame属性是派生属性,取决于图层的位置,anchorPoint,边界和变换。取而代之的是对框架进行动画处理,而不是对框架进行动画处理,而应根据您要实现的效果来设置动画位置或边界。

要移动一个层,你可以动画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"]; 
} 

要调整层,你会动画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"]; 
} 

您可以使用CAAnimationGroup如果结合这些动画您需要同时移动和调整图层大小。

+0

感谢您提供非常有用的链接! – RonLugge 2011-05-12 18:56:33

+0

我被接受的答案抛弃了。谢谢! – 2012-04-03 21:51:20

+3

这应该是被接受的答案。 – CodeReaper 2013-03-28 12:27:30

我们可以改变属性“边界”和“位置”动画它,如

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

问题是古董,但我无论如何都会回答。

框架属性不具动画性。你必须动画其他属性。你也必须禁用隐式动画。

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

下面是一个简单的,完全有效的示例,可以帮助某人。

只要在课上打电话.slideUp(),它就会滑动。

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