如何使用CABasicAnimation为图层框架设置动画?

时间:2010-05-23 18:21:51

标签: iphone core-animation

我想我必须将CGRect转换为一个对象以将其传递给fromValue?

这是我尝试的方式,但它不起作用:

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

6 个答案:

答案 0 :(得分:87)

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组合这些动画。

答案 1 :(得分:6)

我们可以更改“bounds”和“position”的属性来为其设置动画,例如

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

答案 2 :(得分:3)

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

帧属性不可动画。您必须为其他属性设置动画。您还必须禁用隐式动画。

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

答案 3 :(得分:2)

这是一个简单,完整的例子,可以帮助某人。

只需在课程上调用.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()
    }
}

答案 4 :(得分:0)

快速扩展4

import UIKit

extension CALayer {
    func moveTo(point: CGPoint, animated: Bool) {
        if animated {
            let animation = CABasicAnimation(keyPath: "position")
            animation.fromValue = value(forKey: "position")
            animation.toValue = NSValue(cgPoint: point)
            animation.fillMode = .forwards
            self.position = point
            add(animation, forKey: "position")
        } else {
            self.position = point
        }
    }

    func resize(to size: CGSize, animated: Bool) {
        let oldBounds = bounds
        var newBounds = oldBounds
        newBounds.size = size

        if animated {
            let animation = CABasicAnimation(keyPath: "bounds")
            animation.fromValue = NSValue(cgRect: oldBounds)
            animation.toValue = NSValue(cgRect: newBounds)
            animation.fillMode = .forwards
            self.bounds = newBounds
            add(animation, forKey: "bounds")
        } else {
            self.bounds = newBounds
        }
    }

    func resizeAndMove(frame: CGRect, animated: Bool, duration: TimeInterval = 0) {
        if animated {
            let positionAnimation = CABasicAnimation(keyPath: "position")
            positionAnimation.fromValue = value(forKey: "position")
            positionAnimation.toValue = NSValue(cgPoint: CGPoint(x: frame.midX, y: frame.midY))

            let oldBounds = bounds
            var newBounds = oldBounds
            newBounds.size = frame.size

            let boundsAnimation = CABasicAnimation(keyPath: "bounds")
            boundsAnimation.fromValue = NSValue(cgRect: oldBounds)
            boundsAnimation.toValue = NSValue(cgRect: newBounds)

            let groupAnimation = CAAnimationGroup()
            groupAnimation.animations = [positionAnimation, boundsAnimation]
            groupAnimation.fillMode = .forwards
            groupAnimation.duration = duration
            groupAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
            self.frame = frame
            add(groupAnimation, forKey: "frame")

        } else {
            self.frame = frame
        }
    }
}

答案 5 :(得分:-6)

我猜您需要更改最后一行才能使其正常工作:

[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:方法参考中,您可以找到图层如何查找动画以对其属性进行动画处理。