CABasicAnimation, не анимирующий мое свойство

Я пытался понять что не так с моей анимацией, и я все еще не имею, понимают это. Я думаю, что это должно быть действительно прямым, но существует, вероятно, что-то, что я пропускаю, даже после того, чтобы читать партию примеров и документации.

Моя проблема возникает, первоначально формируют то, что на iPhone, Вы не можете изменить размер слоев автоматически (с представлением). В документации говорится иначе, но нет никакого autoresizeMask для слоя в SDKs. Таким образом, я решил сделать немного обходного решения и анимировать слой сам.

У меня есть эта простая часть кода, который должен сделать, простое изменяет размер анимации. Значения хороши, и я даже привел в порядок делегата в трассировке, если anim запускают/заканчивают.

// I've got a property named layerImage (which is a CALayer)
- (void)animateTestWithFrame:(CGRect)value {
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"layerImage.frame"];
    animation.duration = 1;
    animation.fromValue = [NSValue valueWithCGRect:self.frame];
    animation.toValue = [NSValue valueWithCGRect:value];
    animation.removedOnCompletion = YES;
    animation.delegate = self;

    [self.layer addAnimation:animation forKey:@"layerImage.frame"];
}

Так, какие-либо идеи? (Это представление, которое содержит код, является подпредставлением подпредставления окна, если это могло бы иметь значение),

---РЕДАКТИРОВАНИЕ---

Кажется, что кадр не animatable через CABasicAnimation и именованное свойство "кадр". При использовании границ у меня есть некоторый странный результат, но по крайней мере я получаю что-то. Продолжит заниматься расследованиями на этом.

8
задан Sauleil 19 July 2010 в 09:49
поделиться

3 ответа

Хорошо, что вы во всем разобрались, но в вашем ответе на ваш вопрос есть некоторые неточности. Позвольте мне исправить несколько вещей:

Свойство кадра можно анимировать - только не с явной анимацией. Если вы сделаете следующее для слоя, отличного от корневого слоя представления, кадр будет анимирован нормально:

[CATransaction begin];
[CATransaction setAnimationDuration:2.0f];
[animationLayer setFrame:CGRectMake(100.0f, 100.0f, 100.0f, 100.0f)];
[CATransaction commit];

Помните, что установка свойства на слое анимирует это изменение свойства по умолчанию . На самом деле вам нужно отключить анимацию при изменении свойства, если вы не хотите, чтобы оно анимировалось. (Конечно, это верно только в том случае, если вы анимируете слой, отличный от корневого слоя представления.) Вы правы в анимации как позиции, так и границ, если вам нужно использовать явную анимацию.

Вы можете анимировать кадр в UIView, используя неявную анимацию:

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:3.0f];
[[self view] setFrame:CGRectMake(45.0f, 45.0f, 100.0f, 100.0f)];
[UIView commitAnimations];

Это будет анимировать от текущего кадра представления (границы и положение) до x = 45.0, y = 45.0, w = 100.0, h = 100,0.

Похоже, вы также неправильно понимаете разницу между анимацией и слоем. Вы добавляете анимацию к слоям, но добавление анимации к слою не устанавливает автоматически свойство, которое вы анимируете.

CALayers - это объекты модели. Они содержат информацию о слое, который в конечном итоге выводится на экран. Вы должны установить свойство слоя, если хотите, чтобы это свойство действительно имело это значение.Если вы просто анимируете свойство, это будет только визуальное представление, а не реальное - то есть, именно поэтому значение возвращается к исходному значению слоя, потому что вы его никогда не меняли.

Это подводит меня к следующему пункту. Вы сказали:

Используйте animation.removedOnCompletion = НЕТ; animation.fillMode = kCAFillModeForwards; "чтобы убедиться, что значения не сбрасываются в конце анимации

Это не совсем так. Эти два значения просто заставляют анимацию оставаться в своей конечной позиции визуально , однако фактические значения слоя не изменились. Они по-прежнему имеют те же значения, что и при запуске анимации. В общем (за некоторыми исключениями) вы не хотите использовать эти два параметра, потому что они только визуальные . Вы действительно хотите установить значение слоя для свойства, которое вы анимируете.

Скажем, например, вы хотите анимировать положение вашего слоя с помощью явной анимации. Вот код, который вам нужен:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
[animation setFromValue:[NSValue valueWithCGPoint:CGPointMake(70.0f, 70.0f)]];
[animation setToValue:[NSValue valueWithCGPoint:CGPointMake(150.0f, 150.0f)]];
[animation setDuration:2.0f];

// Actually set the position on the *layer* that you want it to be
// when the animation finishes.
[animationLayer setPosition:CGPointMake(150.0f, 150.0f)];

// Add the animation for the position key to ensure that you
// override the animation for position changes with your animation.
[animationLayer addAnimation:animation forKey:@"position"];

Вы также можете рассмотреть возможность группировки анимации. С помощью группы анимации вы можете сгруппировать несколько анимаций вместе, а затем контролировать их взаимосвязь. В вашем случае продолжительность для ваших границ и анимации положения одинакова, поэтому то, что вы пытаетесь сделать, будет нормально работать без группы, но если вы хотите сместить начало анимации, например, вам не нужна позиция анимации для начала до одной или двух секунд в анимации кадра, вы можете пошатнуть их, установив значение beginTime для анимации положения.

Наконец, мне было бы любопытно узнать, почему вы не можете использовать неявную анимацию, доступную в UIView. Я использую их в подавляющем большинстве кода основной анимации, который пишу, и не понимаю, почему это не сработает в вашей ситуации.

С уважением.

26
ответ дан 3 November 2019 в 13:35
поделиться

Ключевой путь должен быть только ключевым путем свойства, но не именем объекта.

Используйте это

[CABasicAnimation animationWithKeyPath:@"frame"]

вместо этого

[CABasicAnimation animationWithKeyPath:@"layerImage.frame"]

И, кстати, когда вы добавляете анимацию к слою, ключ не означает свойство ключа для анимации. Просто ключ (имя), который вы хотите, чтобы эта анимация была (это относится к последней строке вашего кода)

3
ответ дан 3 November 2019 в 13:35
поделиться

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

Итак, в резюме я сделал следующее:

  1. В setFrame создайте 2 анимации со свойством bounds и position.
  2. Используйте «animation.removedOnCompletion = NO; animation.fillMode = kCAFillModeForwards;» чтобы гарантировать, что значения не сбрасываются в конце анимации
  3. Зарегистрируйте делегата в self, чтобы реализовать «animationDidStop: finished:». Похоже, вам все еще нужно установить значения: «layerImage.bounds = [animation.toValue CGRectValue]; layerImage.position = [animation.toValue CGPointValue]; ".

Я не мог использовать систему анимации UIView напрямую, потому что она не делала то, что я хотел на слоях.

Спасибо tadej5553 за то, что указал мне на проблему со слоями, которая у меня возникла с "addAnimation". Вот код для тех, кто хотел бы увидеть, как он выглядит.

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    CABasicAnimation *animation = (CABasicAnimation*)anim;

    if ([animation.keyPath isEqualToString:@"bounds"]) {
        layerImage.bounds = [animation.toValue CGRectValue];
    } else if ([animation.keyPath isEqualToString:@"position"]) {
        layerImage.position = [animation.toValue CGPointValue];
    }
}

- (void)setFrame:(CGRect)value {
    CGRect bounds = CGRectMake(0, 0, value.size.width, value.size.height);

    if ([UIView isAnimationStarted]) {
        // animate the bounds
        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"bounds"];
        animation.duration = [UIView animationDuration];
        animation.fromValue = [NSValue valueWithCGRect:layerImage.bounds];
        animation.toValue = [NSValue valueWithCGRect:bounds];
        animation.removedOnCompletion = NO;
        animation.fillMode = kCAFillModeForwards;
        animation.timingFunction = [UIView animationFunction];
        animation.delegate = self;
        [layerImage addAnimation:animation forKey:@"BoundsAnimation"];

        // animate the position so it stays at 0, 0 of the frame.
        animation = [CABasicAnimation animationWithKeyPath:@"position"];
        animation.duration = [UIView animationDuration];
        animation.fromValue = [NSValue valueWithCGPoint:layerImage.position];
        animation.toValue = [NSValue valueWithCGPoint:CGPointMake(bounds.size.width / 2, bounds.size.height / 2)];
        animation.removedOnCompletion = NO;
        animation.fillMode = kCAFillModeForwards;
        animation.timingFunction = [UIView animationFunction];
        animation.delegate = self;
        [layerImage addAnimation:animation forKey:@"PositionAnimation"];
    } else {
        layerImage.frame = bounds;
    }

    [super setFrame:value];
}
1
ответ дан 3 November 2019 в 13:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: