我一直试图了解我的动画有什么问题,但我还是没弄清楚。我认为这应该是非常直接的,但即使在阅读了大量的例子和文档之后,我也可能会遗漏这些内容。
我的问题最初形成的事实是,在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”进行动画处理。当使用边界时,我得到了一些奇怪的结果,但至少我得到了一些东西。将继续调查此事。
答案 0 :(得分:26)
所以你在这里找到了解决方案很好,但你对自己问题的回答有些不准确。让我纠正一些事情:
框架属性可以动画 - 只是没有显式动画。如果对视图的根层以外的图层执行以下操作,则该框架将生成动画:
[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 = 没有; 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代码中都使用了这些代码,并且无法理解为什么这对你的情况不起作用。
最好的问候。
答案 1 :(得分:3)
密钥路径应该只是属性的关键路径,而不是对象的名称。
使用此
[CABasicAnimation animationWithKeyPath:@"frame"]
而不是
[CABasicAnimation animationWithKeyPath:@"layerImage.frame"]
而且顺便说一句,当你向一个图层添加动画时,该键并不意味着动画的关键属性。只是你想要这个动画的键(名称)(这是指代码的最后一行)
答案 2 :(得分:1)
因此,解决方案是设置图层的@“边界”和@“位置”的动画,因为在iPhone上帧不可动画。我花了一些时间才明白位置是图层的中心,边界的大小是从中心延伸出来的,但这很容易。
所以,我在简历中所做的是:
我无法直接使用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];
}