CABasicAnimation没有动画我的财产

我一直在试图理解我的动画有什么问题,但我仍然没有弄明白。 我认为它应该是非常简单的,但即使在阅读了大量的例子和文档之后,我可能仍然缺少某些东西。

我的问题最初来自于这样一个事实,即在iPhone上,您无法自动调整图层大小(使用视图)。 文档中另有说明,但SDK中没有autoresizeMask层。 所以我决定自己制作一个解决方法并为该图层设置动画。

我有一段简单的代码应该做一个简单的调整大小动画。 值是好的,我甚至设置委托为了追踪如果动画开始/结束。

// I've got a property named layerImage (which is a CALayer)
- (void)animateTestWithFrame:(CGRect)value {
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"layerImage.frame"];
    animation.duration = 1;
    animation.fromValue = [NSValue valueWithCGRect:self.frame];
    animation.toValue = [NSValue valueWithCGRect:value];
    animation.removedOnCompletion = YES;
    animation.delegate = self;

    [self.layer addAnimation:animation forKey:@"layerImage.frame"];
}

那么,有什么想法? (包含代码的这个视图是窗口的子视图的子视图,如果这可能有所作为)

---编辑---

看起来这个框架不是通过CABasicAnimation和命名属性“frame”来设置的。 当使用边界时,我有一些奇怪的结果,但至少我得到了一些东西。 将继续对此进行调查。


所以,你已经在这里弄清楚了,但你对自己问题的回答有一些不准确的地方。 让我纠正一些事情:

框架属性可以是动画的 - 只是没有显式动画。 如果您对视图的根层以外的图层执行以下操作,则框架的动画效果会很好:

[CATransaction begin];
[CATransaction setAnimationDuration:2.0f];
[animationLayer setFrame:CGRectMake(100.0f, 100.0f, 100.0f, 100.0f)];
[CATransaction commit];

请记住,在图层上设置属性会默认动态更改属性。 事实上,如果你不想让它动起来,你必须禁用属性更改的动画。 (当然,这只有在您为视图的根层以外的其他图层设置动画时才是如此。)如果您需要使用显式动画,则在动画设置位置和边界时是正确的。

可以使用隐式动画在UIView上对框架进行动画处理:

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:3.0f];
[[self view] setFrame:CGRectMake(45.0f, 45.0f, 100.0f, 100.0f)];
[UIView commitAnimations];

这将从视图的当前帧(边界和位置)到x = 45.0,y = 45.0,w = 100.0,h = 100.0生成动画。

看起来你也可能误解动画和图层之间的区别。 您将动画添加到图层,但向图层添加动画不会自动设置您正在动画的属性。

CALayers是模型对象。 它们包含关于最终渲染到屏幕的图层的信息。 如果您希望该属性实际具有该值,则必须设置图层的属性。 如果您只是为属性设置动画效果,那么它只会是一种可视化表示,而不是实际的 - 也就是说,这就是为什么值会快速恢复到图层的原始值,因为您从未真正改变过它。

这导致我到下一个点。 你说:

使用“animation.removedOnCompletion = NO; animation.fillMode = kCAFillModeForwards;” 以确保值在动画结束时不会重置

这不完全正确。 这两个值只会导致动画在视觉上保持在最终位置,但是图层的实际值没有改变。 它们仍然与开始动画时的值完全相同。 一般情况下(有一些例外),你不想使用这两个参数,因为它们只是可视化的 。 你想要的是实际设置你的动画属性的图层值。

举例来说,你想用动画显示你的图层的位置。 这是你想要的代码:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
[animation setFromValue:[NSValue valueWithCGPoint:CGPointMake(70.0f, 70.0f)]];
[animation setToValue:[NSValue valueWithCGPoint:CGPointMake(150.0f, 150.0f)]];
[animation setDuration:2.0f];

// Actually set the position on the *layer* that you want it to be
// when the animation finishes.
[animationLayer setPosition:CGPointMake(150.0f, 150.0f)];

// Add the animation for the position key to ensure that you
// override the animation for position changes with your animation.
[animationLayer addAnimation:animation forKey:@"position"];

您可能还想考虑动画分组。 通过动画组,您可以将多个动画组合在一起,然后控制它们之间的相互关系。 在你的情况下,你的界限和位置动画的持续时间是相同的,所以你试图做的没有一个组会工作得很好,但是如果你想抵消动画的开始,例如你不想要位置动画开始,直到一帧或两帧进入帧动画,您可以通过设置位置动画的beginTime值来错开它们。

最后,我很想知道为什么你不能使用UIView上可用的隐式动画。 我在绝大多数我写的Core Animation代码中使用这些代码,并且无法明白为什么这不适合您的情况。

最好的祝福。


关键路径应该只是属性的关键路径,而不是对象的名称。

用这个

[CABasicAnimation animationWithKeyPath:@"frame"]

而不是这个

[CABasicAnimation animationWithKeyPath:@"layerImage.frame"]

只是顺便说一句,当你将动画添加到一个图层时,这个关键并不意味着动画的关键属性。 只是你想要这个动画的关键(名字)(这是指你的代码的最后一行)


因此,解决方案是为图层的@“边界”和@“位置”设置动画,因为在iPhone上帧不是可以动画的。 我花了一些时间才明白,位置是图层的中心,边界的调整大小从中心延伸,但这很容易。

所以,我在简历中所做的是:

  • 在setFrame中,使用边界和位置属性创建2个动画。
  • 使用“animation.removedOnCompletion = NO; animation.fillMode = kCAFillModeForwards;” 以确保值在动画结束时不会重置
  • 注册委托给自己,以实现“animationDidStop:finished:”。 看来你仍然需要设置值:“layerImage.bounds = [animation.toValue CGRectValue]; layerImage.position = [animation.toValue CGPointValue];”。
  • 我无法直接使用UIView动画系统,因为它没有在图层上做我想要的。

    感谢tadej5553指出我与“addAnimation”有关的图层问题。 所以这里是那些想看看它的样子的代码。

    - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
        CABasicAnimation *animation = (CABasicAnimation*)anim;
    
        if ([animation.keyPath isEqualToString:@"bounds"]) {
            layerImage.bounds = [animation.toValue CGRectValue];
        } else if ([animation.keyPath isEqualToString:@"position"]) {
            layerImage.position = [animation.toValue CGPointValue];
        }
    }
    
    - (void)setFrame:(CGRect)value {
        CGRect bounds = CGRectMake(0, 0, value.size.width, value.size.height);
    
        if ([UIView isAnimationStarted]) {
            // animate the bounds
            CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"bounds"];
            animation.duration = [UIView animationDuration];
            animation.fromValue = [NSValue valueWithCGRect:layerImage.bounds];
            animation.toValue = [NSValue valueWithCGRect:bounds];
            animation.removedOnCompletion = NO;
            animation.fillMode = kCAFillModeForwards;
            animation.timingFunction = [UIView animationFunction];
            animation.delegate = self;
            [layerImage addAnimation:animation forKey:@"BoundsAnimation"];
    
            // animate the position so it stays at 0, 0 of the frame.
            animation = [CABasicAnimation animationWithKeyPath:@"position"];
            animation.duration = [UIView animationDuration];
            animation.fromValue = [NSValue valueWithCGPoint:layerImage.position];
            animation.toValue = [NSValue valueWithCGPoint:CGPointMake(bounds.size.width / 2, bounds.size.height / 2)];
            animation.removedOnCompletion = NO;
            animation.fillMode = kCAFillModeForwards;
            animation.timingFunction = [UIView animationFunction];
            animation.delegate = self;
            [layerImage addAnimation:animation forKey:@"PositionAnimation"];
        } else {
            layerImage.frame = bounds;
        }
    
        [super setFrame:value];
    }
    
    链接地址: http://www.djcxy.com/p/12871.html

    上一篇: CABasicAnimation not animating my property

    下一篇: animating a custom CALayer property