使用CoreAnimation同步图像,文本和定位
我是一个有动画的初学者,并且已经尝试了几天的CoreAnimation。 如果这个问题没有意义,请随时警告我,但我正在努力实现以下目标。 我有三个对象:
- 一个应该是一个图像,根据给定的模式移动
- 一个应该是交换两个图像的UIImage
- 一个应该是内容发生变化的文本(CATextLayer?)
这三个动作应该同步进行。
例如,考虑一个显示正弦函数的程序,如在ECG中,在-1和+1之间振荡:第一个图像将根据当前值(-1,-0.9,-0.8,… 0,+ 0.1,+ 0.2,… 1),交换图像的正值显示“+”,负值显示“ – ”,文本将在“正”和“负”之间交替显示。
我尝试过使用CAAnimationGroup,但我显然遗漏了一些东西。 一些代码:
{ // image that moves CALayer *img1 = [CALayer layer]; img1.bounds = CGRectMake(0, 0, 20, 20); img1.position = CGPointMake(x1,y1); UIImage *img1Image = [UIImage imageNamed:@"image.png"]; img1.contents = (id)img1Image.CGImage; // image that changes CALayer *swap = [CALayer layer]; swap.bounds = CGRectMake(0, 0, 30, 30); swap.position = CGPointMake(x2,y2); NSString* nameswap = @"img_swap_1.png" UIImage *swapImg = [UIImage imageNamed:nameswap]; // text CATextLayer *text = [CATextLayer layer]; text.bounds = CGRectMake(0, 0, 100, 100); text.position = CGPointMake(x3,y3); text.string = @"Text"; // create animations CGFloat duration = 0.2; CGFloat totalDuration = 0.0; CGFloat start = 0; NSMutableArray* animarray = [[NSMutableArray alloc] init]; NSMutableArray* swapanimarray = [[NSMutableArray alloc] init]; NSMutableArray* textanimarray = [[NSMutableArray alloc] init]; float prev_x = 0; float prev_y = 0; // I get my values for moving the object for (NSDictionary* event in self.events) { float actual_x = [[event valueForKey:@"x"] floatValue]; float actual_y = [[event valueForKey:@"y"] floatValue]; // image move animation CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"]; CGPoint startPt = CGPointMake(prev_x,prev_y); CGPoint endPt = CGPointMake(actual_x, actual_y); anim.duration = duration; anim.fromValue = [NSValue valueWithCGPoint:startPt]; anim.toValue = [NSValue valueWithCGPoint:endPt]; anim.beginTime = start; anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; [animarray addObject:anim]; // image swap animation CABasicAnimation *swapanim = [CABasicAnimation animationWithKeyPath:@"contents"]; swapanim.duration = duration; swapanim.beginTime = start; NSString* swapnamefrom = [NSString stringWithFormat:@"%@.png", prev_name]; NSString* swapnameto = [NSString stringWithFormat:@"%@.png", current_name]; UIImage *swapFromImage = [UIImage imageNamed:swapnamefrom]; UIImage *swapToImage = [UIImage imageNamed:swapnameto]; swapanim.fromValue = (id)(swapFromImage.CGImage); swapanim.toValue = (id)(swapToImage.CGImage); swapanim.fillMode = kCAFillModeForwards; swapanim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; [swapanimarray addObject:swapanim]; //text animation CABasicAnimation *textanim = [CABasicAnimation animationWithKeyPath:@"contents"]; textanim.duration = duration; textanim.fromValue = @"Hey"; textanim.toValue = @"Hello"; textanim.beginTime = start; [textanimarray addObject:textanim]; // final time settings prev_x = actual_x; prev_y = actual_y; start = start + duration; totalDuration = start + duration; } } CAAnimationGroup* group = [CAAnimationGroup animation]; [group setDuration:totalDuration]; group.removedOnCompletion = NO; group.fillMode = kCAFillModeForwards; [group setAnimations:animarray]; CAAnimationGroup* swapgroup = [CAAnimationGroup animation]; [swapgroup setDuration:totalDuration]; swapgroup.removedOnCompletion = NO; swapgroup.fillMode = kCAFillModeForwards; [swapgroup setAnimations:swapanimarray]; CAAnimationGroup* textgroup = [CAAnimationGroup animation]; [textgroup setDuration:totalDuration]; textgroup.removedOnCompletion = NO; textgroup.fillMode = kCAFillModeForwards; [textgroup setAnimations:textanimarray]; [ball addAnimation:group forKey:@"position"]; [swap addAnimation:flaggroup forKey:@"position"]; [text addAnimation:textgroup forKey:@"contents"]; [self.layer addSublayer:ball]; [self.layer addSublayer:swap]; [self.layer addSublayer:text]; }
现在……问题:
1)交换图像在每次交换时恢复为原始图像。 所以,如果我交换A-> B,我看到它在预期的持续时间内从A到B,但后来又回到A.我已经在SO上阅读了很多关于此的线程,但无法使其工作。
2)以定时方式更改文本层的字符串…这可能是基础设施吗? 基本上,我试图在第一个图像移动时立即更改文本和交换图像,如示例中所述。
3)设置CABasicAnimation的委托没有任何影响,尽管它适用于CAAnimationGroup:因此,您不能为每个动画管理像animationDidStop这样的事件,只针对整个组。 有没有其他方法可以这样做?
4)从3)开始,是否有可能使用CAAnimationGroup拦截事件以创建停止/启动行为? 我们假设我想要播放/停止按钮,并从我离开它的位置恢复动画?
作为一个结论性的问题,我只想知道是否有人做了类似的事情,最重要的是,如果这种做事方式(使用CAAnimationGroup)实际上是要走的路,或者是否更好地使用CAKeyFrameAnimation或其他东西。
我设法解决了这个问题,尽管有一些解决方法。
1)这里的诀窍是
removedOnCompletion = NO; fillMode = kCAFillModeForwards;
需要分配给每个动画,而不是CAAnimationGroup。
2)这需要为CATextLayer确定单独的动画,并为“string”属性设置动画。 在这种情况下,代码是正确的,除了应该有的“内容”键值
[text addAnimation:textgroup forKey:@"contentAnimate"];
或者,请参见第3点。回调操作方式允许更改label.text。
3)实现此目的的唯一方法是实际上不使用CAAnimationGroup并设置CABasicAnimation序列。 一般模式是:在函数中创建第一个CABasicAnimation,分配委托。 在animationDidStop方法中,向创建CABasicAnimation的函数添加回调。 这样,每个动画都将被创建。 同时,这允许拦截并响应动画中的特定事件。
-(void)performNextAnimation:(int)index { // ... this gives for granted you have an object for #index ... NSDictionary* thisEvent = [self.events objectAtIndex:index]; float prev_x = [thisEvent valueForKey:@"prev_x"]; float prev_y = [thisEvent valueForKey:@"prev_x"]; float actual_x = [thisEvent valueForKey:@"prev_x"]; float actual_y = [thisEvent valueForKey:@"prev_x"]; CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"]; GPoint startPt = CGPointMake(prev_x,prev_y); CGPoint endPt = CGPointMake(actual_x, actual_y); anim.duration = 0.5; anim.fromValue = [NSValue valueWithCGPoint:startPt]; anim.toValue = [NSValue valueWithCGPoint:endPt]; anim.beginTime = start; [anim setDelegate:self]; anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; [object addAnimation:anim forKey:@"position"]; } - (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag { // ... your conditions go here ... // ... your actions go here ... // eg set label.text [self performNextAnimation]; }
4)从3开始,这在CAAnimationGroup中是不可能的。 阅读文档,我想说CAAnimationGroup并不打算用于每个事件代表一个时间步骤的序列(为此你需要使用CAKeyFrameAnimation或CABasicAnimation序列和回调函数,就像我做的那样)。 CAAnimationGroup用于应该以全有或全无的方式执行的链接动画(类似于CATransaction)。