Iphone 如何使用CABasicAnimation设置层框架的动画?

Iphone 如何使用CABasicAnimation设置层框架的动画?,iphone,core-animation,Iphone,Core Animation,我想我必须将CGRect转换成一个对象才能将其传递给fromValue 我是这样尝试的,但它不起作用: CABasicAnimation *frameAnimation = [CABasicAnimation animationWithKeyPath:@"frame"]; frameAnimation.duration = 2.5; frameAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTi

我想我必须将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"];

我想您需要更改最后一行以使其正常工作:

[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:
方法参考中,您可以找到层如何查找动作以设置其属性的动画。

CALayer的帧属性是派生属性,取决于层的位置、锚点、边界和变换。您不应该设置帧的动画,而应该设置位置或边界的动画,这取决于您试图实现的效果

要移动层,可以设置
位置的动画

-(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"];
}
要调整层的大小,您需要设置
边界
参数的动画:

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

我们可以更改“边界”和“位置”的属性来设置动画,例如

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

谢谢弗拉基米尔。我发现CALayer无法直接设置frame属性的动画。文件上说是在一个灰色的盒子里。不知什么原因,我没有看到它。最后一行很好-在addAnimation中指定的键可以是任意字符串。我认为真正的答案是铍的下面
[myLayer addAnimation:frameAnimation forKey:@“frame”]
frame
只是动画的一个名称,与动画的实际属性无关……我认为您可以在本QA的上下文中进行动画制作:感谢您提供了非常有用的链接!这个答案(技术问答)已经过时了。只放链接的问题是它们死了,答案就没用了。因此,应该扣除每一个链接张贴点。SMH。可以用一个动画来设置变换属性的动画以实现移动和调整动画大小吗?愿主基督亲自来保佑你的灵魂