Alternative to performSelector:withObject:afterDelay: for animating views consequantially - ios

I have method -(void)animationStart that consist a lot of [self performSelector:#selector(myAnimation) withObject:nil afterDelay: 21 * 0.01]; with different method's and delays.
How can I refactor my code not to use performSelector? I use it for make animation consequentially change.

You don't specify how you exactly perform the animations themselves, but with UIView animation blocks you can also specify a delay.(animateWithDuration:delay:options:animations:completion:).
Alternatively you can use NSTimerfor performing delays.
But for a detailed answer you should provide more details on how you perform your animation.
Update
Using animation blocks is very straightforward...In the completion block (see code below) you can start the follow up animation (for series of animations). For parallel animation processing you just start multiple blocks of animations...there are different messages. If you don't need to handle the animation end, you can use the ones without completion block.
Here is an example:
[UIView animateWithDuration:2.0 delay:0.1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
// perform animation code here
} completion:^(BOOL finished) {
// This code is performed after the animation is completed. E.g. you can start a new animation here
// (for serial animation processing):
}];

Related

Block-Based Animation does not Work: Animations and Completion Blocks are Executed Immediately (Without Duration)

I tried to animate some features of the UIView, anyway, I simplified everything to these code lines in "ViewController.m":
- (void)viewDidLoad {
...
[UIView animateWithDuration: 5.0 animations:^{
NSLog(#"animations");}
completion:^(BOOL finished){NSLog(#"completion");}];
}
Both blocks outputs immediately after loading despite the fact that animation should last five seconds.
You can't use block animations in viewDidLoad because the UIView you want to animate doesn't have superview at the present moment. Move the code to the viewDidAppear method.

ios animation. How nested animations affect duration?

Let's say I have a timed UIAnimation, in the format of
[UIView animateWithDuration:DURATION_X
animations:^
{
[function that might contain a separate animation with DURATION_Y]
}
completion:^(BOOL finished)
{
[function that might contain a separate animation with DURATION_Z]
}];
If the nested animations also have durations inside them, how does that affect the outer animation? Are the inner animations executed with DURATION_Y and DURATION_Z, respectively, no matter what DURATION_X happens to be? Or is DURATION_Y animations scaled down or curtailed to end with respect to DURATION_X, assuming DURATION_X <= DURATION_Y?
Basically, what I'm asking in a nutshell is how we can control duration of inner animations safely, to ensure they execute with DURATION_Y (and not some shorter version) even when the outermost animation has a different and shorter DURATION_X?
AFAIU, the inner animation takes control over the duration which is mentioned in the outer animation block. Whereas, function inside the completion block does not seem to wait until the main animation block finishes its animation task with the given time duration.
So, lets say DURATION_X is 5 seconds, DURATION_Y is 20 seconds and DURATION_Z is 10 seconds respectively. What happens is that the animation function inside the completion block gets triggered once the control completes (going to the function and do whatever) the main animation block (Having said the function inside the main animation block does have a different time duration). Hence, the function inside the completion block gets executed with the DURATION_Z and it does animate for the exact duration mentioned in DURATION_Z.
Along the side, the function inside the main animation block gets executed for the time duration specified in the DURATION_X ONLY. It ignores the time duration of DURATION_Y. A wacky code snippet here is:
-(void)doSomeAnim
{
[UIView animateWithDuration:5.0
animations:^
{
[self animateOrangeBoy];
}
completion:^(BOOL finished)
{
[self animateBlueBoy];
}];
}
-(void)animateOrangeBoy
{
[UIView animateWithDuration:20.0 animations:^{
orangeView.frame = CGRectMake(orangeView.frame.origin.x, orangeView.frame.origin.y + 300, orangeView.frame.size.width, orangeView.frame.size.height);
}];
}
-(void)animateBlueBoy
{
[UIView animateWithDuration:10.0 animations:^{
blueView.frame = CGRectMake(blueView.frame.origin.x, blueView.frame.origin.y + 300, blueView.frame.size.width, blueView.frame.size.height);
}];
}
So, animateBlueBoy also starts along with the animateOrangeBoy but animateOrangeBoy lasts only 5 seconds but animateBlueBoy goes till 10 seconds.

ios - How to force animations to execute sequentially in a loop?

I have a priority queue of various actions -- UIImageView translations and the HP bar decreases associated with them. I already programmed a bar widget with CALayer animations, so it should handle itself, but for some reason, even though my loop is sequential, all the animations -- bar animations as well as other actions in the queue -- all happen simultaneously. How do I force sequentiality? Here's code from my viewController .m:
while (![selectedMoves isEmpty])
{
SelectedMove* nextMove = [selectedMoves dequeueMax];
// Move the user to clearly indicate who is moving:
[self animateAttacker:nextMove.user];
[moveReporter setText:report];
[self executeMove:nextMove];
}
executeMove is the wrapper that changes the health bar value to reflect damage.
-(void) executeMove:(SelectedMove*)attack
{
... calculate damage dealt by attack...
// Animate HP bar change on-screen
double percentage = (double)[currentHP intValue] / (double)[currentStats[HP] intValue];
[playerHealthBars[slot] updateBarPercentage:percentage andMaxHP:[currentStats[HP] intValue]];
}
My issue is that all of the healthBar animations, as well as the "animateAttacker" calls, are happening at once on the screen. What command forces one to execute before the other, or forces a screen refresh before moving on?
animateAttacker is the wrapper that translates the appropriate UIImage forward according to nextMove.
The goal is to have each iteration of the loop -- the health bar and the animateAttacker -- execute simultaneously, or sequentially, and to have separate iterations execute in the order of the loop:
:
-(void)animateAttacker:(HonmonBattleState*)attacker
{
UIImageView* attackerImageView = playerImages[index];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
attackerImageView.transform=CGAffineTransformMakeTranslation(ATTACK_PERTURBATION, -ATTACK_PERTURBATION);
[UIView commitAnimations];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
attackerImageView.transform=CGAffineTransformIdentity;
[UIView commitAnimations];
}
Thanks for your help!
PS> I can use CALayer Core Animations or UIView animations. I have done both, and the health bars are internally done using layers.
Block-based UIView animations have completion blocks that you can use to chain animations, see this thread over here.
And you can use completion blocks in CAAnimations with this category on GitHub (it's on CocoaPods if you need).
If you want a global, serial queue for your animations, you should look into having your own NSOperationQueue with a maximum parallel task count of one. This way, all operations you run on it will be delayed until the previous ones have finished.

How can I control UIView animation repeat cycle?

I'm afraid that the title is correct english expression but,
I have an animation on iOS with 4 scenes.
I used setAnimationDidStopSelector: method.
Here's the question: How can I make stopping function for the animation?
In iOS 4 and later you should use block based animation. Using these newer methods you can very easily specify some code to run once the animation has finished. For example:
[UIView animateWithDuration:1.0
animations:^{
// This code will be animated for 1 second.
[anObject setAlpha:0.0];
}
completion:^(BOOL finished) {
// This code will be executed once the animation has completed.
[anObject removeFromSuperview];
}];
A little ugly, but pretty lazy:
add a flag to know when it should animate, and when not. Put your animation under if block (or something same) and just switch flag when you need.

UIView Animate Doesn't Respect Delay?

Why does this not work?
[UIView animateWithDuration:0 delay:3 options:0 animations:^(void) {
NSLog(#"after duration, please!");
} completion:nil];
The NSLog fires immediately.
I'm not looking for workarounds (there are many), but rather wondering why this would be.
The intermediate frames of core animation are actually happening in another background thread. The first and last frame of the animation are often created immediately. So the NSLog can fire in the main UI thread without waiting or even knowing about any background animation in progress.

Resources