2 анимации на один и тот же объект, показывает только последний. Как показать первый без блока завершения вложенности?

Я делаю две анимации в одном и том же UIImageView, используя блоки. Анимации не совсем спина к спине, но почти; между ними есть какая-то логика.

  • анимировать UIImageView из одного места представления в другое.
  • выполнить логику, которая определяет, разрешено ли изображению оставаться там
  • если это не разрешено, отменить анимацию (UIImageView возвращается в исходное положение)

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

В не вложенной конфигурации, почему iOS хочет сократить предыдущие анимации и выполнить только последнюю, и как я могу заставить ее ждать первую анимацию, прежде чем переходить к следующей? Я не думаю, что ему нужно блокировать основной поток или «сидеть и вращаться» в блоке завершения; Я просто хочу, чтобы все анимации были показаны. Пытался добавить задержку ко второй анимации безрезультатно.

Это работа для CAKeyframeAnimation?

// first animation

[UIView animateWithDuration:0.5
                      delay:0.0
                    options: UIViewAnimationCurveLinear
                 animations:^{movingColor.center = newCenter;
                     movingColor.transform = scaleTransform;}
                 completion:^(BOOL finished){ NSLog(@"forward animation done");}];

if (/* ...color is allowed at that location */) {

    // do some stuff

} else {

    // undo the animation

    [UIView animateWithDuration:0.5
                          delay:0.0
                        options: UIViewAnimationCurveLinear
                     animations:^{movingColor.center = origCenter;
                         movingColor.transform = scaleTransform;}
                     completion:^(BOOL finished){ NSLog(@"back animation done");}];
}

person andrewmobile    schedule 17.06.2012    source источник
comment
Смешно о некрасивом и неуместном. Я тоже часто так делаю: оцениваю код по тому, как он выглядит на странице. Синтаксис блока (особенно с вложением) немного неуклюж, но здесь он мощный и уместен. Возня с таймингами неточна (и не так читабельна... представьте, что вы приходите позже и пытаетесь выяснить, что происходит, читая эти постоянные времени). Блок завершения предназначен именно для того, что нужно сделать по завершении. Может быть, немного некрасиво, но правильно. Смотрите мой ответ, чтобы узнать, как это сделать и стать немного красивее.   -  person danh    schedule 17.06.2012


Ответы (3)


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

- (void)moveColor:(UIView *)view to:(CGPoint)center delay:(NSTimeInterval)delay completion:(void (^)(BOOL finished))complete {

    [UIView animateWithDuration:0.5 delay:delay options:UIViewAnimationCurveLinear animations:^{
        view.center = center;
        view.transform = scaleTransform;  // probably don't need this
    } completion:completion];
}

Таким образом, ваша логика может быть отделена от кода анимации.

- (void)someMethod {

    [self moveColor:movingColor to:newCenter delay:0.0 completion:^(BOOL finished) {
        if (/*it can stay*/) {
            // stuff
        } else {
            [self moveColor:movingColor to:origCenter delay:2.0 completion:^(BOOL finished) {}];
        }
    }];
}
person danh    schedule 17.06.2012

Правильный способ сделать это, как вы сказали, установить второй в завершении первого, что является правильным способом,

Вы также можете добавить задержку при запуске другого, это может работать или не работать, это зависит от множества переменных.

Ваша вторая анимация будет иметь задержку 0,5 (время завершения первой анимации).

[UIView animateWithDuration:0.5
                      delay:0.5
                    options: UIViewAnimationCurveLinear
                 animations:^{movingColor.center = origCenter;
                     movingColor.transform = scaleTransform;}
                 completion:^(BOOL finished){ NSLog(@"back animation done");}];
person Omar Abdelhafith    schedule 17.06.2012

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

Если вы хотите указать пользователю, что что-то не так, запустив анимацию, но не завершив ее, вы можете выполнить вторую анимацию с задержкой. Не забудьте также установить параметр UIViewAnimationOptionBeginFromCurrentState, если вы задерживаете вторую анимацию на время, меньшее, чем продолжительность первой:

[UIView animateWithDuration:0.5 
                      delay:0.25 //or some number
                    options: (UIViewAnimationCurveLinear | UIViewAnimationOptionBeginFromCurrentState)
                 animations:^{movingColor.center = origCenter;
                     movingColor.transform = scaleTransform;}
                 completion:^(BOOL finished){ NSLog(@"back animation done");}];
person Svein Halvor Halvorsen    schedule 17.06.2012