Как мне оживить CATransform3Ds с CAKeyframeAnimation?
Я использовал CAKeyframeAnimations для анимации свойств слоя transform.rotation
и transform.translation.x
, но у меня возникли проблемы с анимированием свойства transform
неявно. У меня есть слой, который должен анимироваться между двумя состояниями, а интерполяция по умолчанию CABasicAnimation абсолютно неверна и не соответствует пути, который я хочу. CAKeyframeAnimation на помощь, или так я думал. Любая попытка анимации transform
с использованием CAKeyframeAnimation приводит к тому, что представление сразу же привязывается к окончательному преобразованию, пока выполняются другие анимации. Если я удалю первую половину следующей функции и пусть мои "трансформирующие" события используют CABasicAnimation в нижней части, она оживляет просто отлично, хотя с неверно интерполированными преобразованиями на этом пути.
Мой делегат слоя реализовал следующее:
- (id <CAAction>) actionForLayer:(CALayer *)layer forKey:(NSString *)event
{
if ([event isEqualToString:@"transform"])
{
CGSize startSize = ((CALayer *)self.layer.presentationLayer).bounds.size;
CGSize endSize = self.layer.bounds.size;
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:event];
animation.duration = 0.25;
NSMutableArray *values = [NSMutableArray array];
int stepCount = 10;
for (int i = 0; i < stepCount; i++)
{
CGFloat p = i / (float)(stepCount - 1);
CGSize size = [self interpolateBetweenSize:startSize andSize:endSize percentage:p];
CATransform3D transform = [self transformForSize:size];
[values addObject:[NSValue valueWithCATransform3D:transform]];
}
animation.values = values;
return animation;
}
// All other animations use this basic animation
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:event];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.removedOnCompletion = YES;
animation.fillMode = kCAFillModeForwards;
animation.duration = 0.25;
return animation;
}
Мое преобразование - это перевод, за которым следует поворот, но я думаю, что групповая анимация с отдельными анимациями ключевого кадра, анимация через перевод и поворот приведет к сумасшедшему городу. Я подтвердил, что размер и преобразование верны для всех значений p, которые я прохожу, и p строго варьируется от 0 до 1.
Я попытался установить функцию синхронизации по умолчанию, я попытался установить массив временных функций, я опустил ключевые слова, я установил repeatCount из 0, removedOnCompletion = YES и fillMode вперед, и это не имело никакого эффекта. Я не правильно создаю анимацию ключевого кадра трансформирования?
Ответы
Ответ 1
Этот метод работал в iOS 3, но, похоже, был сломан в iOS 5.0.
5.1 "волшебным образом" исправлено это, похоже, это ошибка в iOS 5.0. Я бы установил радар, но теперь он работает в формате 5.1.
@Gsnyder: Некоторые предпосылки: я экспериментирую с Clear-like UI (для чего-то совершенно не связанного с Clear) и придумал это: http://blog.massivehealth.com/post/18563684407/clear. Это должно объяснить необходимость поворота и перевода.
С тех пор я создал переход затвора, который подразделяет представление на N слоев (вместо 2), которые выглядят так, если смотреть со стороны://///.
Мой код не анимирует границы, он использует размер на каждом шаге для определения необходимого преобразования.
@Paul.s: Implicit позволяет мне сохранить эту абстракцию внутри самого класса слоев, не загрязняя контроллер представления, которому он принадлежит. Контроллер вида должен просто изменять границы, и слой должен двигаться соответствующим образом. Я не являюсь поклонником контроллеров представлений, имеющих десятки пользовательских анимаций, когда сами представления могут справиться с этим.
Мне нужно использовать анимацию ключевого кадра, потому что анимация по умолчанию между слоями трансформируется/и _ анимируется с помощью неправильных углов, поэтому слои /// \ не выравниваются по всему преобразованию. Анимации ключевого кадра гарантируют правильное выравнивание краев, пока все они ожидают.
Я рассматриваю это закрытое, похоже, это ошибка в iOS 5.0 и с тех пор исправлена. Спасибо всем.
Ответ 2
(void)animateViewWith3DCurrentView:(UIView *)currentView withPoing:(CGPoint)movePoint
{
//flip the view by 180 degrees in its place first.
currentView.layer.transform = CATransform3DRotate(currentView.layer.transform,myRotationAngle(180), 0, 1, 0);
//set the anchor point so that the view rotates on one of its sides.
currentView.layer.anchorPoint = CGPointMake(0.5, 0.5);
//Set up scaling
CABasicAnimation *resizeAnimation = [CABasicAnimation animationWithKeyPath:kResizeKey];
//we are going to fill the screen here. So 423,337
[resizeAnimation setToValue:[NSValue valueWithCGSize:CGSizeMake(423, 337)]];
resizeAnimation.fillMode = kCAFillModeForwards;
resizeAnimation.removedOnCompletion = NO;
// Set up path movement
UIBezierPath *movePath = [UIBezierPath bezierPath];
//the control point is now set to centre of the filled screen. Change this to make the path different.
// CGPoint ctlPoint = CGPointMake(0.0, 0.5);
CGPoint ctlPoint = CGPointMake(1024/2, 768/2);
//This is the starting point of the animation. This should ideally be a function of the frame of the view to be animated. Hardcoded here.
// Set here to get the accurate point..
[movePath moveToPoint:movePoint];
//The anchor point is going to end up here at the end of the animation.
[movePath addQuadCurveToPoint:CGPointMake(1024/2, 768/2) controlPoint:ctlPoint];
CAKeyframeAnimation *moveAnim = [CAKeyframeAnimation animationWithKeyPath:kPathMovement];
moveAnim.path = movePath.CGPath;
moveAnim.removedOnCompletion = YES;
// Setup rotation animation
CABasicAnimation* rotateAnimation = [CABasicAnimation animationWithKeyPath:kRotation];
//start from 180 degrees (done in 1st line)
CATransform3D fromTransform = CATransform3DMakeRotation(myRotationAngle(180), 0, 1, 0);
//come back to 0 degrees
CATransform3D toTransform = CATransform3DMakeRotation(myRotationAngle(0), 0, 1, 0);
//This is done to get some perspective.
CATransform3D persp1 = CATransform3DIdentity;
persp1.m34 = 1.0 / -3000;
fromTransform = CATransform3DConcat(fromTransform, persp1);
toTransform = CATransform3DConcat(toTransform,persp1);
rotateAnimation.toValue = [NSValue valueWithCATransform3D:toTransform];
rotateAnimation.fromValue = [NSValue valueWithCATransform3D:fromTransform];
//rotateAnimation.duration = 2;
rotateAnimation.fillMode = kCAFillModeForwards;
rotateAnimation.removedOnCompletion = NO;
// Setup and add all animations to the group
CAAnimationGroup *group = [CAAnimationGroup animation];
[group setAnimations:[NSArray arrayWithObjects:moveAnim,rotateAnimation, resizeAnimation, nil]];
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
group.duration = 0.7f;
group.delegate = self;
[group setValue:currentView forKey:kGroupAnimation];
[currentView.layer addAnimation:group forKey:kLayerAnimation];
}