UPDATE
: (I redid my functions so all the animations won't be as nested as before. Still no luck)
I have a piece of code where a try to, in this order:
Hide view A
Show view B
Show view C
The order is important!
The code is the following :
Main function:
[fileMenuController hide:0.2 andDelay:0.1];
[drawingToolController show:0.2 andDelay:0.2];
[penSizeMenuController showSubViewWithDuration:0.4];
fileMenuController hide function:
[UIView animateWithDuration:duration //begin animation
delay:delay
options:UIViewAnimationCurveEaseIn
animations:^{
[self.view setFrame:CGRectOffset([self.view frame], 0, -self.view.frame.size.height)];
}
completion:nil
];
drawingToolController show function:
[UIView animateWithDuration:duration //begin animation
delay:delay
options:UIViewAnimationCurveEaseIn
animations:^{
[self.view setFrame:CGRectOffset([self.view frame], 0, self.view.frame.size.height)];
}
completion:nil
];
penSizeController show function:
[UIView transitionWithView:self.view
duration:duration
options:UIViewAnimationOptionTransitionCurlDown
animations:^{ [self.view addSubview:subView] ;}
completion:nil];
self.view.alpha = 1;
My problem is the block penSizeController showSubView starts with the first animation (fileMenuController hide)!
The first two animations (fileMenuController hide and drawingToolController show) are working properly. When fileMenuController hide is done, drawingToolController starts.
So, does somebody know why the part in the penSizeController showSubView block starts at the same time as the first animation?
I'd imagine it's because the outer animation block doesn't have any animation – because the hide and show creates inner animation blocks – so it immediately calls the completion block.
Either remove the nested animation block in hide and show or add a parameter that disables animation for these nested animation actions.
Related
I am using block based animations to simulate dealing cards as an intro animation for a game. The animation works great unless the user causes a segue to fire DURING the animation, where we perform additional animations in order to get the effect a "sliding" transition from source to destination view controller. What happens now is the cards that have already been "dealt" slide off screen appropriately, and if there are cards that have not been dealt, it deals it in the middle of the transition and then the card disappears when the destination view controller is pushed. It's very ugly.
I have tried 'view.layer removeAllAnimations' which didn't help (I did import quartzcore). What I want to do is cancel the pending animations in the completion blocks, and simply perform the segue animations.
Here's the "dealing" code:
[UIView animateWithDuration:0.20f
delay:0.20f
options:UIViewAnimationOptionCurveEaseOut
animations:^
{
_fiveOfHearts.center = CGPointMake(90, 198);
_fiveOfHearts.transform = fiveOfHeartsTransform;
}
completion:^(BOOL finished)
{[UIView transitionWithView:_fiveOfHearts duration:0.20f options:UIViewAnimationOptionTransitionFlipFromRight animations:^{
_fiveOfHearts.image = [UIImage imageNamed:#"52"];
}completion:nil];
[UIView animateWithDuration:0.30f
delay:0.0f
options:UIViewAnimationOptionCurveEaseOut
animations:^
{
_jackOfHearts.center = CGPointMake(128, 196);
_jackOfHearts.transform = jackfHeartsTransform;
}
completion:^(BOOL finished)
{[UIView transitionWithView:_jackOfHearts duration:0.40f options:UIViewAnimationOptionTransitionFlipFromRight animations:^{
_jackOfHearts.image = [UIImage imageNamed:#"112"];
}completion:nil];
[UIView animateWithDuration:0.30f
delay:0.0f
options:UIViewAnimationOptionCurveEaseOut
animations:^
{
_aceOfHearts.center = CGPointMake(162, 196);
_aceOfHearts.transform = aceOfHeartsTransform;
}
completion: ... and so on.
The segue code looks something like:
for (UIView *iv in src.view.subviews) {
if (iv.tag != 99999) {
[UIView animateWithDuration:0.5f animations:^{iv.center = CGPointMake(iv.center.x - 600, iv.center.y);}];
}
}
You could add a global BOOL say hasUserSkippedOn once the user presses to move on set it to YES and then every time you hit a completion block check if _hasUserSkipped is still YES then do not proform any more. Normally on blocks it has a default end bool but I am not too sure if animations blocks have the end bool.
In one of my views i need to animate frame property of a UIImageView and while doing it i want to show a progress bar(UIProgressView) in the title view of the navigation bar.The problem is the if i comment out the following animation blocks the progress bar is updated as expected smoothly.On the other hand due to the following animation the progress bar stops in severals places and carries incrementing again.
//add message bubble
[UIView animateWithDuration:0.3
delay:0
options:UIViewAnimationOptionAllowUserInteraction
animations:^
{
animationBubbleImageView.alpha = 1;
}
completion:^(BOOL finished)
{
[self removeAutoCorrectionAndHighlight];
[UIView animateWithDuration:0.3
delay:0
options:UIViewAnimationOptionAllowUserInteraction
animations:^
{
CGRect bubbleFrame = CGRectMake(animationBubbleImageView.frame.origin.x,
animationBubbleImageView.frame.origin.y,
bubbleSize.width,
bubbleSize.height);
[animationBubbleImageView setFrame:bubbleFrame];
messageLabel.alpha = 1;
}
completion:^(BOOL finished)
{
[self sendSubviewToBack:textView];
[self.delegate moveBubbleToTableCell];
}];
}];
animation blocks do not block the main thread but what coudl be the reason of unsmooth beahviout of th progress view ?
UPDATE: What i want to achive is the MessagesApp bubble animation in IOS.While the typed message becomes a bubble and flies to its place the progress bar should increment slowly.
If i try the same thing withou animation progressbar increments normal.
Try putting the progress bar animation in the same animation as the bubble animation. Or put them all into an animation group.
Have you tried Instruments to see what's happening?
Wild guess: you can also check whether the two views inadvertently overlap.
If feasible you can also try to group together the animations, as suggested by "Dad".
Best, Akos
I'm trying to animate a label embedded in a UIView.
this is the code :
-(void)displayText:(NSString*)text {
[label setText:text];
[UIView animateWithDuration:5.0
delay:0.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
[labelView setAlpha:1.0];
}
completion:nil
];
[UIView animateWithDuration:5.8
delay:0.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
[labelView setAlpha:0.0];
}
completion:nil
];
}
To verify, the method is called, i set a breakpoint.
The calls return immediatly but only the end of animations is displayed.
I wired the UIView to the controller.
Pls help, I'm stuck.
Thanks in advance !
Patrick
Correct,
When you animate views like this the animation doesn't actually happen on screen until the next pass of the runloop (i.e. once your method returns).
UIView will coalesce animations that are programmed sequentially.
Use the completion block to fade back out. The code looks a bit odd but it works great!
[UIView animateWithDuration:5.0
delay:0.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{
[labelView setAlpha:1.0];
}
completion:^(BOOL completed){
[UIView animateWithDuration:5.8
delay:0.0
options:UIViewAnimationOptionCurveEaseIn
animations:^{[labelView setAlpha:0.0];}
completion:nil];
}];
In response to your comments:
The animations won't start until the next run of the runloop. They won't start until your app finishes what its doing. If you wait in the loop you will have the same problem and also freeze up your interface. Consider using individual labels for each letter, and add a progressively bigger delay for each animation. All these animation instructions will be queued up at once and then played out over the course of the next however many seconds. Imagine you are like a movie director, you tell each actor what to do in the next scene. Then, once everyone knows what to do you sit back and yell "action" and watch it all play out.
I try to use animationWithDuration and transitionWithView to create one big animation. I want to do something like this :
Move view A with animationWithDuration
After step1 is completed, move view B with animationWithDuration
After step2 is completed, show view C with transitionWithView (With OptionCurlDown)
I really look over the net, and i don't know how to correclty do that. My problem is that the step 3 start always at the same time as step A. If i do only step 1 and step 2, this is ok, i mean, step 2 starts only when step 1 is done. But i had no luck with step 3!
I also tried to nest transitionWithView inside an animationWithDuration, but the result is the same,
THank you
Update
The following is the code itself :
Main function:
[fileMenuController hide:0.2 andDelay:0.1];
[drawingToolController show:0.2 andDelay:0.2];
[penSizeMenuController showSubViewWithDuration:0.4];
fileMenuController hide function:
[UIView animateWithDuration:duration //begin animation
delay:delay
options:UIViewAnimationCurveEaseIn
animations:^{
[self.view setFrame:CGRectOffset([self.view frame], 0, -self.view.frame.size.height)];
}
completion:nil
];
drawingToolController show function:
[UIView animateWithDuration:duration //begin animation
delay:delay
options:UIViewAnimationCurveEaseIn
animations:^{
[self.view setFrame:CGRectOffset([self.view frame], 0, self.view.frame.size.height)];
}
completion:nil
];
penSizeController show function:
[UIView transitionWithView:self.view
duration:duration
options:UIViewAnimationOptionTransitionCurlDown
animations:^{ [self.view addSubview:subView] ;}
completion:nil];
self.view.alpha = 1;
penSizeController show always starts at the same time as fileMenuController hide
Update to resolve the problem
Following the idea of user523234 , i did that :
MainFunction
[fileMenuController hide:0.2 andDelay:0.1];
[drawingToolController show:0.2 andDelay:0.2];
[self performSelector:#selector(delayedPenSizeMenuShow)withObject:nil afterDelay:0.4)
MainFunction (newFunction)
-(void) delayedPenSizeMenuShow{
[penSizeMenuController showSubViewWithDuration:0.4];
}
This way, it works, penSizeMenuController is called after the 2 animations. But i am wondering is it is ok with the new block base philosophy with ios 4.0?
But well, at least i have somethin..
I have a subView that I want to toggle between hidden and not hidden by a button. How do I fade in the subview and fade it out? For now it just appears immediately and disappear immediately when I toggle the button.
I am wondering what is the easiest way to do this animation.
Thanks
On iOS 4.0+ Apple recommends you use their new, block-based animation methods. Using these, the code would look something like this:
[UIView animateWithDuration:2.0
animations:^{myView.alpha = 0.0;}];
The properties you are animating go inside the block (the ^{...} part). Blocks are sort of like functions, so you can put multiple lines of code inside of them, if you want to animate multiple properties. For example:
[UIView animateWithDuration:0.2
animations:^{
view.alpha = 0.0;
view.backgroundColor = [UIColor redColor];
}];
If you need to perform an action after the animation is complete, use the +animateWithDuration:animations:completion: method (which also uses blocks), for example:
[UIView animateWithDuration:0.2
animations:^{view.alpha = 0.0;}
completion:^(BOOL finished){ [view removeFromSuperview]; }];
For more info, check out the UIView Class Reference 'Animations' section and 'Animating Views with Blocks' section.
This is the old pre-4.0 way:
http://objcolumnist.com/2009/07/18/simple-uiview-based-animations-on-the-iphone/
... which has the advantage of being conceptually simple and easy to implement.
float alpha = 1.0; // or 0.0 if it's already visible and you want to fade out
[UIView beginAnimations:#"" context:NULL];
[UIView setAnimationDuration:2.0]; // seconds, not ms. guess how i know?
[mySubView setAlpha:alpha];
[UIView commitAnimations];