我是一个有动画的初学者,并且已经尝试使用CoreAnimation几天了。如果这个问题没有意义,请随时警告我,但我正在努力实现以下目标。我有三个对象:
这三个动作应该同步进行。
作为一个例子,考虑一个显示正弦函数的程序,如在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或其他什么东西其他
答案 0 :(得分:1)
我设法解决了这个问题,尽管有一些解决方法。
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 ...
// e.g. set label.text
[self performNextAnimation];
}
4)从3开始,这在CAAnimationGroup中是不可能的。阅读文档,我会说CAAnimationGroup不打算用于每个事件代表一个时间步骤的序列(为此你需要使用CAKeyFrameAnimation或CABasicAnimation序列和回调函数,就像我做的那样)。 CAAnimationGroup适用于应该以全有或全无的方式执行的链接动画(类似于CATransaction)。