I am trying to convert some animation code that uses beginAnimations to use animation blocks. The problem that I am having is that when I use the animations blocks the animations goes much faster and I cannot seem to adjust the speed by changing the duration value
This is what I started with originally:
birdFly.image = [UIImage imageNamed: #"bird1.png"];
[self.view addSubview:birdFly];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:20];
birdFly.frame = CGRectMake(-1116,27,111,48);
[UIView commitAnimations];
[birdFly release];
This is what I tried first to replace what I had above. Using this code the animation is much faster than what it was using the original code. Even changing the duration does not seem to change the speed at all:
birdFly.image = [UIImage imageNamed: #"bird1.png"];
[self.view addSubview:birdFly];
[UIView animateWithDuration:20
animations:^{
birdFly.frame = CGRectMake(-1116,27,111,48);
}];
I also tried this, thinking I needed a completion block, but the speed was still just as fast compared with what I had originally when I wasn't using blocks.
birdFly.image = [UIImage imageNamed: #"bird1.png"];
[self.view addSubview:birdFly];
UIViewAnimationOptions options = UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction;
[UIView animateWithDuration:20 delay:0.0 options:options animations:^
{
birdFly.frame = CGRectMake(-1116,27,111,48);
} completion:nil];
Is the code all doing the same thing? Am I just missing something very simple here? I thought increasing the duration would make the bird go slower and decreasing it would make it go faster, but it doesn't seem to have any impact t all when change it using blocks.
Any guidance would be appreciated.
Thanks.
Aaron
If your animation block is occurring within another animation block, -animateWithDuration:animations: will inherit the duration of the outer block. Try adding UIViewAnimationOptionOverrideInheritedDuration to the options list (and possibly UIViewAnimationOptionOverrideInheritedCurve if you need to override the curve too).
Related
I have a UIView animation block which uses the UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoReverse option so it keeps going, but at some points I need to stop the animation but more importantly stop it and have the view return to its original position.
I have tried [dot1.layer removeAllAnimations]; but that stops it in its tracks without returning it to its original position, it stops mid animation.
I have tried stopping it then just running a second animation to return it to its correct frame, but that can be a bit jerky as I don't know how far it needs to go with what duration etc.
So is it possible to simply have the animation stop after it's completed its last cycle rather than mid way?
You should try this:
[UIView animateWithDuration:2 delay:0 options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction animations:^
{
view.frame = CGRectMake(0, 100, 200, 200);
} completion:^(BOOL finished)
{
if(! finished) return;
}];
And to stop the animation use this:
[view.layer removeAllAnimations];
I've tried the accepted solution and it didn't work for me. The animations just stopped after one run. Digging around on the net leads me to believe that [self.view.layer removeAllAnimations] is the recommended way to stop animations (another method can be seen in the following link as the asker's comment to the accepted solution
Stop an auto-reverse / infinite-repeat UIView animation with a BOOL / completion block).
The way that worked for me was the one given by BooRanger (even jrturton accepted it). I set a boolean property called stopAnimations in the class and initialise its value to NO. Whenever I want to stop the animations, I set stopAnimations to YES and then call [self.view.layer removeAllAnimations] in the next line. Then in the completion block, I do the following.
if(self.stopAnimations){
self.finishAnimations = NO;
return;
}
Hope this helps the someone. :)
There are two main documented methods of animating UIViews. One, is a deprecated process in which one makes multiple calls beginning with method beginAnimations:context: and the other, newer, suggested approach is block-based.
I have the following code in my application. However, only the older deprecated animation segment works. The newer, block-based approach works the first time, but every subsequent time skips directly to the end of the animation and shows me only the final frame immediately. Has anybody had any experienced with this?
-(void)updateImageViewSlider:(UIImage *)image {
mImageFeedSwipe.alpha = 0.0;
[mImageFeedSwipe setHidden:NO];
mImageFeedSwipe.frame = DEFAULT_IMAGEVIEW_RECT;
[mImageFeedSwipe setImage:image];
//
// The following animation code works fine.
//
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:1.0];
mImageFeedSwipe.alpha = 1.0;
[mImageFeedSwipe setFrame:NEW_IMAGEVIEW_RECT];
[UIView commitAnimations];
//
// The following DOES NOT work except on the first run
//
int animationOptions = 0
| UIViewAnimationOptionCurveEaseInOut
| UIViewAnimationOptionBeginFromCurrentState
| UIViewAnimationOptionAllowUserInteraction;
[UIView animateWithDuration:1.0
delay:0
options:animationOptions
animations:^{
// Bring in the swiping image view...
mImageFeedSwipe.alpha = 1.0;
[mImageFeedSwipe setFrame:NEW_IMAGEVIEW_RECT];
}
completion:nil];
}
This is being run on the main thread via [self performSelectorOnMainThread...].
I was seeing this same problem until I realized that in between animations I was hiding the view and never changing view.hidden to NO again. Any chance that you are hiding your view or setting alpha to 0.0 in between animations?
So I attempt to flip between two images, but the duration is seemingly ignored.
I understand that Apple has to do some animation very quickly to keep the magic alive, but is there a way to slow down the flipping?
My current object hierarchy is game board contains many cards which inherit from UIView.
A card has a face and back that are UIViews that host a UIImage and other data
[UIView animateWithDuration:15.0
animations:^(void) {
cardOne.center =CGPointMake(100, 100);
cardTwo.center =CGPointMake(100, 100);
//low level calls, to directly perform the image swap
[cardOne.face removeFromSuperview];
[cardOne addSubview:cardOne.back];
[cardOne sendSubviewToBack:cardOne.face];
//calling the transitionFromView to do the image swap
[UIView transitionFromView:cardOne.face
toView:cardOne.back
duration:10
options:UIViewAnimationTransitionFlipFromLeft
completion:^(BOOL finished){ }];
Thanks for your feedback. I attempted a mix of all you input and it did end up working correctly. I don't yet know why though.
Thanks for your responses. I tried reverting to the old style and it worked. I have not figured out why as yet.
The non-working code is commented out and the working code is left uncommented.
Thanks again
/*
[UIView animateWithDuration:animationDuration
animations:^{
[self.face removeFromSuperview];
[self addSubview:self.back];
[self sendSubviewToBack:self.face];
}];
*/
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:kDefaultFlipSpeed];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft
forView:self
cache:YES];
[self.face removeFromSuperview];
[self addSubview:self.back];
[self sendSubviewToBack: self.face];
[UIView commitAnimations];
I cant ask in a comment, so:
Have you tried with less than 10 seconds? More precisely between 0-1 second. Something like 0.5 seconds. Tell me if you notice any change in duration with these values.
My quick answer would be:
Try setting 10 seconds as 10.0 or 10.0f.
Hope it helps.
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];
It appears to me these two class methods are not interchangeable. I have a subview of UIView with the following code in the touchesBegan method:
if (!highlightView) {
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Highlight"]];
self.highlightView = tempImageView;
[tempImageView release];
[self addSubview:highlightView];
}
highlightView.alpha = 0.0;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
highlightView.alpha = 1.0;
[UIView commitAnimations];
When I touch the Button, the highlight fades in, like you would expect. When I touch up immediately (before the animation is finished), my touchesEnded gets called. This is the behavior I want.
But now, I've become a big fan of blocks and try to use them wherever possible. So I replaced the UIView animation code with this:
[UIView animateWithDuration:0.2 animations:^{
highlightView.alpha = 1.0;
}];
Results: the highlight still fades in as expected, but if I touch up before the animation is finished, my touchesEnded does not get called. If I touch up after the animation is finished, my touchesEnded does get called. What's going on here?
The new animation blocks in iOS 4 by default disable user interaction. You can pass in an option to allow views to respond to touches during animation using bit flags in conjunction with the animateWithDuration:delay:options:animations:completion method of UIView as such:
UIViewAnimationOptions options = UIViewAnimationOptionCurveLinear | UIViewAnimationOptionAllowUserInteraction;
[UIView animateWithDuration:0.2 delay:0.0 options:options animations:^
{
highlightView.alpha = 1.0;
} completion:nil];
Documentation
One more thing is that Appple doesn't recommend to use [UIView beginAnimations:context:], you can find it in beginAnimations docs
Use of this method is discouraged in iOS 4.0 and later. You should use
the block-based animation methods to specify your animations instead.
Probably Apple can mark old methods as deprecated in the future releases and won't support them, so using block-based methods is really more preferable way for performing animation.