2013-07-30 2 views
3
void (^first_animation)(); 
void (^second_animation)(BOOL finished); 


// First animation 

first_animation = ^() 
{ 
    g_pin_info_screen.view.alpha = 1.0; 
}; 


// Second animation 

second_animation = ^(BOOL finished) 
{ 
    g_shadow_layer.opacity = 0.0; 

    void (^set_opacity_to_1)(); 

    set_opacity_to_1 = ^() 
    { 
     g_shadow_layer.opacity = 1.0; 
    }; 

    [UIView animateWithDuration : 2.0 
      delay    : 0.0 
      options    : UIViewAnimationCurveEaseInOut 
      animations   : set_opacity_to_1 
      completion   : nil 
    ]; 

}; 



// Begin the animations 

{ 

    float duration; 

    duration = 0.35; 

    [UIView animateWithDuration : duration 
      delay    : 0.00 
      options    : UIViewAnimationCurveEaseInOut 
      animations   : first_animation 
      completion   : second_animation 
    ]; 

} 

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

Надеюсь, что кто-нибудь может прокомментировать, является ли приведенная выше схема правильным способом этого или нет.

ответ

11
__block NSMutableArray* animationBlocks = [NSMutableArray new]; 
typedef void(^animationBlock)(BOOL); 

// getNextAnimation 
// removes the first block in the queue and returns it 
animationBlock (^getNextAnimation)() = ^{ 

    if ([animationBlocks count] > 0){ 
     animationBlock block = (animationBlock)[animationBlocks objectAtIndex:0]; 
     [animationBlocks removeObjectAtIndex:0]; 
     return block; 
    } else { 
     return ^(BOOL finished){ 
      animationBlocks = nil; 
     }; 
    } 
}; 

[animationBlocks addObject:^(BOOL finished){ 
    [UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{ 
     //my first set of animations 
    } completion: getNextAnimation()]; 
}]; 


[animationBlocks addObject:^(BOOL finished){ 
    [UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{ 
     //second set of animations 
    } completion: getNextAnimation()]; 
}]; 



[animationBlocks addObject:^(BOOL finished){ 
    [UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{ 
     //third set 
    } completion: getNextAnimation()]; 
}]; 


[animationBlocks addObject:^(BOOL finished){ 
    [UIView animateWithDuration:duration delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{ 
     //last set of animations 
    } completion:getNextAnimation()]; 
}]; 

// execute the first block in the queue 
getNextAnimation()(YES); 
+0

Спасибо за ответ. Это немного больше, чем я думал. Но это очень сложно. Вы пробовали это в своем проекте? – Stanley

+0

Он хорошо работает и чище для множества прикованных анимаций. Если вы попытаетесь связать кучу анимаций в блоке завершения блока анимации UIView, он может стать уродливым. Однако, если у вас есть только несколько анимаций, это немного перебор. – JeffRegan

+0

В принципе, это создает очередь анимаций и срабатывает один за другим. UIViewAnimationOptionCurveLinear гарантирует, что анимация будет гладкой. – JeffRegan

0

Вы должны приковать их вместе с помощью + (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion

В options: аргумента, вам необходимо включить UIViewAnimationOptionBeginFromCurrentState

Удачи!

+0

изменил вариант «show_shadow» в: UIViewAnimationCurveEaseInOut | UIViewAnimationOptionBeginFromCurrentState. Но результат тот же. Больше намеков? – Stanley

+0

Это неясно, это не объясняет, как цепочки. две анимации differnet. – AlexWien

+0

В блоке «Начать анимацию» я поместил вторую анимацию «show_shadow» в аргумент «завершение». – Stanley

0

В обработчике завершения первой анимации запустите второй.

+0

Думаю, я сделал то, что вы предложили в блоке с надписью «Начать анимацию». Прошу прокомментировать, если это на самом деле то, что вы предложили. – Stanley

+0

Да, но почему продолжительность анимации 0,00, это должно быть более высокое значение. Далее Quart2d gudie также связывает анимацию цепочки с помощью обработчика завершения. – AlexWien

+0

Угадайте, что вы неправильно прочитали кодировку, это «задержка», которая была установлена ​​на 0.00. Длительность была установлена ​​равной 0,35 через переменную. Но теперь все выглядит нормально. Если мое последнее тестирование правильное, проблема связана с CALayer. Если используется UIView, все должно быть в порядке. – Stanley

2

С помощью библиотеки третьей стороны, есть решение, которое выглядит, как показано ниже:

Во-первых, для удобства, определить категорию UIView как так:

+(RXPromise*) rx_animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations 
{ 
    RXPromise* promise = [RXPromise new]; 
    [UIView animateWithDuration:duration animations:animations: ^(BOOL finished){ 
     // ignore param finished here 
     [promise fulfillWithValue:@"finished"]; // return just a string indicating success 
    }];  
    return promise; 
} 

Тогда , определяют любое количество асинхронных анимаций, которые выполняются один за другим, следующим образом:

[UIView rx_animateWithDuration:duration animation:^{ 
     ... //define first animation 
    }] 
.then(^id(id result){ 
    // ignore result, it contains the fulfill value of the promise, which is @"finished" 
    return [UIView rx_animateWithDuration:duration animation:^{ 
     ... // define second animation 
    }]; 
}, nil) 
.then(^id(id result){ 
    return [UIView rx_animateWithDuration:duration animation:^{ 
     ... // define third animation 
    }]; 
}, nil) 
.then(^id(id result){ 
    return [UIView rx_animateWithDuration:duration animation:^{ 
     ... // and so force 
    }; 
}, nil); 

Вышеприведенное утверждение является асинхронным!

С одной линии дополнительного кода вы можете добиться отмены:

RXPromise* rootPromise = [UIView rx_animateWithDuration:duration animation:^{ 
     ... //define first animation 
    }]; 

rootPromise.then(^id(id result){ 
    return [UIView rx_animateWithDuration:duration animation:^{ 
     ... // define second animation 
    }]; 
}, nil) 
.then(^id(id result){ 
    return [UIView rx_animateWithDuration:duration animation:^{ 
     ... // define third animation 
    }]; 
}, nil) 
... 

// later, in case you need to cancel pending animations: 
[rootPromise cancel]; 

"RXPromise" Библиотека доступна на GitHub: RXPromise. Он специально разработан для этих случаев использования и многое другое. Из-за полное раскрытие информации: Я автор;)

+0

Это почти работает, так как мы говорим об анимации, вам нужно просто позвонить thenOnMain. –

+0

PS Было бы неплохо иметь возможность генерировать обещание, которое будет вызываться на main, независимо от того, вызывается ли тогда или thenOnMain. –

+0

@ShayErlichmen Я предположил, что 'animateWithDuration: анимации:' * can * можно вызывать из не основного потока. Если нет, то да - мы должны использовать 'thenOnMain';) – CouchDeveloper

1

Просто проверьте здесь: https://gist.github.com/vadimsmirnovnsk/bce345ab81a1cea25a38

Вы можете приковать его в функциональном стиле:

dispatch_block_t animationsBlock = ^{ 
    [self.view updateConstraintsIfNeeded]; 
    [self.view layoutIfNeeded]; 
}; 

[[[[[[[[[BARAnimation construct] 
    initially:animationsBlock] 
    animationWithDuration:0.425 animationConditions:^{ 
     [gridView mas_updateConstraints:^(MASConstraintMaker *make) { 
      make.top.equalTo(imageView).with.offset(32.0); 
     }]; 
    } animations:animationsBlock] 
    animationWithDuration:0.425 animationConditions:^{ 
     [gridView mas_updateConstraints:^(MASConstraintMaker *make) { 
      make.top.equalTo(imageView).with.offset(0.0); 
     }]; 
    } animations:animationsBlock] 
    animationWithDuration:0.425 animationConditions:^{ 
     [gridView mas_updateConstraints:^(MASConstraintMaker *make) { 
      make.top.equalTo(imageView).with.offset(-32.0); 
     }]; 
    } animations:animationsBlock] 
    animationWithDuration:0.425 animationConditions:^{ 
     [gridView mas_updateConstraints:^(MASConstraintMaker *make) { 
      make.top.equalTo(imageView).with.offset(0.0); 
     }]; 
    } animations:animationsBlock] 
    animationWithDuration:0.8 animationConditions:nil animations:^{ 
     foreView.alpha = 1.0; 
    }] 
    finally:^{ 
     [self.didEndSubject sendNext:[RACUnit defaultUnit]]; 
     [self.didEndSubject sendCompleted]; 
    }] 
    run]; 
Смежные вопросы