Я немного новичок в анимации и пару дней экспериментировал с CoreAnimation. Не стесняйтесь предупредить меня, если этот вопрос не имеет смысла, но я пытаюсь добиться следующего. У меня есть три объекта:
- должно быть изображение, движущееся по заданному шаблону
- один должен быть UIImage, который меняет местами два изображения
- должен быть текст (CATextLayer?), содержимое которого изменяется
Три действия должны выполняться синхронно.
В качестве примера представьте программу, показывающую синусоидальную функцию, как в ЭКГ, колеблющуюся между -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 или что-то еще.