-->

无法获得动画中的CALayer的当前位置(Cannot get current position o

2019-07-05 09:25发布

我想实现的动画,当你按下一个按钮,它动画块下来,当你松开,它蓬勃生机回升到原来的位置,但我不能获得动画块的当前位置,不管是什么。 这里是我的代码:

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

}

但行

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

只返回目的地位置不是当前位置。 我需要基本上给我的容器这就是动画一旦我松开按钮的当前位置,这样我就可以进行下一个动画。 我现在不工作。

Answer 1:

我还没有分析你的代码足以成为100%肯定,为什么[[container.layer presentationLayer] frame]可能不会返回你所期望的。 但是,我看到几个问题。

一个明显的问题是, moveDown:没有声明movePath 。 如果movePath是一个实例变量,你可能要清除或创建一个新的实例每次moveDown:叫,但我没有看到你这样做。

一个不太明显的问题是,(从你使用的判断removedOnCompletionfillMode ,尽管你使用的presentationLayer ),你显然不明白的Core Animation是如何工作的。 这被证明是非常普遍的,所以请原谅我,如果我错了。 无论如何,请继续阅读,因为我将解释如何动画作品的核心,然后如何解决你的问题。

在核心动画,你通常与工作层的对象是一个模型层 。 当您将动画层,核心动画创建模型层的副本,称为表示层和动画随时间变化的展现层的性能。 动画永远不会改变模型层的特性。

当动画结束,并且(默认)被移除时,表示层被破坏,模型层的属性的值再次生效。 所以在屏幕上层出现“弹回”到原来的位置/颜色/不管。

解决这个问题的一个常见的,但错误的方法是设置动画的removedOnCompletionNO及其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];
}

请注意,我们给了动画的关键,当我把它添加到层。 由于我们使用相同的密钥每一次,每一个新的动画将取代(删除)之前的动画,如果动画之前还没有完成。

当然,只要你玩这个,你会发现,如果你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];
}

如果你真的需要它是一个动画组中的keyPath动画,你的问题应该告诉我们你为什么需要这些东西。 无论如何,它与那些东西太多:

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

你可以找到我的测试程序的完整代码在这个要点 。 只要创建一个新的单一视图应用项目和替换的内容ViewController.m与要点的内容。



文章来源: Cannot get current position of CALayer during animation