动画期间无法获取CALayer的当前位置

Mat*_*att 12 calayer cakeyframeanimation caanimation ios cgrect

我试图实现一个动画,当你按住一个按钮时,它会向下动画一个块,当你释放时,它会将它动画回原来的位置,但无论如何我都无法获得动画块的当前位置.这是我的代码:

-(IBAction)moveDown:(id)sender{

   CGRect position = [[container.layer presentationLayer] frame];

    [movePath moveToPoint:CGPointMake(container.frame.origin.x, position.y)];

    [movePath addLineToPoint:CGPointMake(container.frame.origin.x, 310)];

    CAKeyframeAnimation *moveAnim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    moveAnim.path = movePath.CGPath;
    moveAnim.removedOnCompletion = NO;
    moveAnim.fillMode = kCAFillModeForwards;


    CAAnimationGroup *animGroup = [CAAnimationGroup animation];
    animGroup.animations = [NSArray arrayWithObjects:moveAnim, nil];
    animGroup.duration = 2.0;
    animGroup.removedOnCompletion = NO;
    animGroup.fillMode = kCAFillModeForwards;

    [container.layer addAnimation:animGroup forKey:nil];
}
-(IBAction)moveUp:(id)sender{
     CGRect position = [[container.layer presentationLayer] frame];

    UIBezierPath *movePath = [UIBezierPath bezierPath];

    [movePath moveToPoint:CGPointMake(container.frame.origin.x, position.y)];

    [movePath addLineToPoint:CGPointMake(container.frame.origin.x, 115)];

    CAKeyframeAnimation *moveAnim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    moveAnim.path = movePath.CGPath;
    moveAnim.removedOnCompletion = NO;
    moveAnim.fillMode = kCAFillModeForwards;

    CAAnimationGroup *animGroup = [CAAnimationGroup animation];
    animGroup.animations = [NSArray arrayWithObjects:moveAnim, nil];
    animGroup.duration = 2.0;
    animGroup.removedOnCompletion = NO;
    animGroup.fillMode = kCAFillModeForwards;

    [container.layer addAnimation:animGroup forKey:nil];

}
Run Code Online (Sandbox Code Playgroud)

但行

   CGRect position = [[container.layer presentationLayer] frame];
Run Code Online (Sandbox Code Playgroud)

只返回目标位置而不是当前位置.我需要基本上给我一个容器的当前位置,一旦我释放按钮动画,所以我可以执行下一个动画.我现在所做的不起作用.

rob*_*off 44

我没有足够的分析你的代码100%确定为什么[[container.layer presentationLayer] frame]可能不会返回你的期望.但我看到了几个问题.

一个明显的问题是moveDown:没有声明movePath.如果movePath是实例变量,您可能希望每次moveDown:调用它时清除它或创建一个新实例,但我不认为您这样做.

一个不太明显的问题是,(从你使用的判断removedOnCompletionfillMode,尽管你使用的presentationLayer),你显然不明白的Core Animation是如何工作的.事实证明这是非常普遍的,所以如果我错了,请原谅我.请继续阅读,因为我将解释Core Animation的工作原理以及如何解决您的问题.

在Core Animation中,您通常使用的图层对象是模型图层.将动画附加到图层时,Core Animation会创建模型图层的副本(称为表示图层),动画会随时间更改表示图层的属性.动画永远不会更改模型图层的属性.

当动画结束并且(默认情况下)被删除时,表示层将被销毁,模型图层属性的值将再次生效.因此,屏幕上的图层似乎"快速恢复"到其原始位置/颜色/等等.

一个常见的,但错误的解决这个问题的办法是设置动画的removedOnCompletion,以NO及其fillModekCAFillModeForwards.执行此操作时,表示层会挂起,因此屏幕上没有"快照".问题是,现在您的表示层与模型层的值不同.如果您询问模型图层(或拥有它的视图)的动画属性值,您将获得一个与屏幕上的值不同的值.如果您尝试再次为该属性设置动画,则动画可能会从错误的位置开始.

要为图层属性设置动画并使其"粘贴",您需要更改模型图层的属性值,然后应用动画.这样,当移除动画并且表示层消失时,屏幕上的图层看起来完全相同,因为模型图层具有与动画结束时其表示层相同的属性值.

现在,我不知道为什么你使用关键帧为直线运动设置动画,或者为什么要使用动画组.这里似乎没有必要.你的两种方法实际上是相同的,所以让我们分解出常见的代码:

- (void)animateLayer:(CALayer *)layer toY:(CGFloat)y {
    CGPoint fromValue = [layer.presentationLayer position];
    CGPoint toValue = CGPointMake(fromValue.x, y);

    layer.position = toValue;

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    animation.fromValue = [NSValue valueWithCGPoint:fromValue];
    animation.toValue = [NSValue valueWithCGPoint:toValue];
    animation.duration = 2;
    [layer addAnimation:animation forKey:animation.keyPath];
}
Run Code Online (Sandbox Code Playgroud)

请注意,当我将动画添加到图层时,我们会为动画添加一个键.由于我们每次都使用相同的键,因此如果先前的动画尚未完成,则每个新动画将替换(移除)先前的动画.

当然,只要你玩这个,你会发现,如果你moveUp:moveDown:只完成了一半,该moveUp:动画将显示为半速,因为它仍然有2秒,但只有一半的持续时间尽量去旅行.我们应该根据要行驶的距离来计算持续时间:

- (void)animateLayer:(CALayer *)layer toY:(CGFloat)y withBaseY:(CGFloat)baseY {
    CGPoint fromValue = [layer.presentationLayer position];
    CGPoint toValue = CGPointMake(fromValue.x, y);

    layer.position = toValue;

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    animation.fromValue = [NSValue valueWithCGPoint:fromValue];
    animation.toValue = [NSValue valueWithCGPoint:toValue];
    animation.duration = 2.0 * (toValue.y - fromValue.y) / (y - baseY);
    [layer addAnimation:animation forKey:animation.keyPath];
}
Run Code Online (Sandbox Code Playgroud)

如果你真的需要它作为动画组中的键路径动画,你的问题应该告诉我们你为什么需要这些东西.无论如何,它也适用于这些事情:

- (void)animateLayer:(CALayer *)layer toY:(CGFloat)y withBaseY:(CGFloat)baseY {
    CGPoint fromValue = [layer.presentationLayer position];
    CGPoint toValue = CGPointMake(fromValue.x, y);

    layer.position = toValue;

    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:fromValue];
    [path addLineToPoint:toValue];

    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    animation.path = path.CGPath;
    animation.duration =  2.0 * (toValue.y - fromValue.y) / (y - baseY);

    CAAnimationGroup *group = [CAAnimationGroup animation];
    group.duration = animation.duration;
    group.animations = @[animation];
    [layer addAnimation:group forKey:animation.keyPath];
}
Run Code Online (Sandbox Code Playgroud)

您可以在此要点中找到我的测试程序的完整代码.只需创建一个新的单视图应用程序项目,并将内容替换ViewController.m为要点的内容.

  • 观看来自WWDC 2011的[Session 421 - 核心动画要素](https://developer.apple.com/videos/wwdc/2011/?id=421)视频.这只是一个小时,它非常**信息. (4认同)