Как анимировать CATransform3D с помощью CAKeyframeAnimation? - PullRequest
13 голосов
/ 02 марта 2012

Я использовал CAKeyframeAnimations для анимации свойств слоя transform.rotation и transform.translation.x, но у меня возникают проблемы с неявной анимацией свойства transform. У меня есть слой, который должен анимироваться между двумя состояниями, и интерполяция по умолчанию в CABasicAnimation полностью неверна и не идет по желаемому пути. CAKeyframe Анимация на помощь, или я так подумал. Любая попытка анимировать transform с использованием CAKeyframeAnimation приводит к тому, что представление немедленно привязывается к финальному преобразованию во время выполнения других анимаций. Если я удаляю первую половину следующей функции и позволяю моим событиям «transform» использовать 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;
}

Мое преобразование - это перевод, за которым следует поворот, но я думаю, что групповая анимация с анимацией отдельных ключевых кадров, анимируемой с помощью перевода И поворот, приведет к сумасшедшему городу. Я подтвердил, что size & transform верны для всех значений p, которые я передаю, и p строго варьируется от 0 до 1.

Я попытался установить функцию синхронизации не по умолчанию, я попытался установить массив функций синхронизации, я пропустил keyTImes, я установил repeatCount 0, УдаленныйOnCompletion = YES, и fillMode of вперед, и это не имело никакого эффекта. Правильно ли я создаю анимацию ключевого кадра преобразования?

Ответы [ 2 ]

0 голосов
/ 27 марта 2012

Этот метод работал в iOS 3, но, похоже, был сломан в iOS 5.0.

5.1 «волшебным образом» исправили это, это казалось ошибкой в ​​iOS 5.0. Я бы заполучил радар, но теперь он работает в 5.1.

@ Гснидер: Некоторое предыстория: я экспериментировал с интерфейсом, похожим на Clear (для чего-то совершенно не связанного с Clear), и придумал следующее: http://blog.massivehealth.com/post/18563684407/clear. Это должно объяснить необходимость поворота и перевода.

С тех пор я создал переход затвора, который делит вид на N слоев (а не только на 2), который выглядит так, если смотреть сбоку: /////.

Мой код не анимирует границы, он использует размер на каждом шаге для определения необходимого преобразования.

@Paul.s: Implicit позволяет мне сохранить эту абстракцию в самом классе слоя, не загрязняя контроллер представления, которому он принадлежит. Контроллер вида должен просто изменять границы, и слой должен двигаться соответствующим образом. Я не фанат контроллеров представления, имеющих десятки пользовательских анимаций, когда сами представления могут с этим справиться.

Мне нужно использовать анимацию по ключевым кадрам, потому что анимация по умолчанию между слоями преобразует / и _ анимирует через неправильные углы, чтобы слои /// \ не выстраивались в линию по всему преобразованию. Анимация ключевого кадра обеспечивает правильное выравнивание краев, пока они все анимируются.

Я считаю, что это закрыто, похоже, это ошибка в iOS 5.0 и с тех пор исправлена. Спасибо всем.

0 голосов
/ 15 марта 2012
(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];   
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...