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. :)
Related
I wrote the following code :
Code:
[MyImage setHighlighted:true];
Sleep(1);
[MyImage setHighlighted:false];
i need to highlight my image for one second and after that get it back , but X-Code when arrive to [MyImage setHighlighted:true] do not any thing ( i know it do it ) and after that Sleep executed and main thread of application goes to sleep for 1 second and after that the last line executed , but my question is why the first line do not update the UI and i can,t see any thing in user interface .
In first line of code the Sleep method do not executed and main thread is in normal state and it should set my image to highlight and after that goes to sleep for 1 second and after that set my image to normal state , but why not ?
I know that i can use NSTimer to do it but why the following code do not work ?
Thanks .
jackslash explains well what is happening.
You can change your code into something like this:
[image setHighlighted:true];
[self performSelector:#selector(aMethodThatChangesTheHighlight) withObject:self afterDelay:1];
Finally note that freezing the main thread is generally a bad idea.
changes to the screen are only made once your method returns. Changes are then all coalesced and made at once. In this case as you are sleeping the main thread your method does not return until you un highlight the image. After your method returns UIKit looks to see if it needs to draw any changes. As you have undone your changes before your method returned there is nothing to do so no change happens on the display.
The best thing to do would be to see if you can use the UIView class animation methods.
[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationCurveEaseInOut
animations:^{
//animation code goes here
//note that you have to change something that UIView considers to be animatable
//e.g.
self.myView.alpha = 0;
} completion:^(BOOL done){
//code to execute once the animation has completed goes here
}];
I like sch's answer better, but if you wanted to use animation as jackslash suggested, you would have to make the animation change something visual so that the completion block does not run immediately. Not even adding a "delay" will fix that.
MyImage.alpha = 0.99f;
[UIView animateWithDuration:1.0f delay:0.0f options:UIViewAnimationOptionAllowUserInteraction animations:^{
MyImage.alpha = 1.0f;
[MyImage setHighlighted:YES];
} completion:^(BOOL finished) {
[MyImage setHighlighted:NO];
}];
i noticed some strange behavior. When i start a animation and change the View (the view will not dismissed!), the completion handler never get called.
[UIView animateWithDuration:0.1f
delay:0.0f
options:UIViewAnimationCurveEaseOut
animations:^(void){
[myView setHidden:YES];
myLabel.alpha = 0.0f;
someOtherView.frame = CGRectMake(130, bubbleBigRect.origin.y, 61, 65);
[button setHidden:YES];
}
completion:^(BOOL finished){
NSLog(#"Complete %d",finished);
[imageVIew setImage:[UIImage imageNamed:#"myPng.png"]];
}];
}
is there any solution for this?
Don't know where to write it, but I get the same thing that you have, but in my case the completion block was sometimes called. It might be same thing.
I found out that if in the animation block has nothing was animate- for example, if you set alpha=0 to uiview that is alpha is already 0, or you set content offset to UIScrollView to the same content offset (like in my case), the completion block not called.
Put this in your animation block, and put everything you want to do on completion in YOUR_SELECTOR method. You can now do whatever you want with your view and still have a way of executing something on completion!
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(YOUR_SELECTOR)];
In my case the view which I was animating has its frame set to (0,-568,320,568) and after animation I forget to change the frame to its required position i.e. (0,0,320,568) so the completion block was not being called. Changing the frame of the animated view did the job for me. So I can say if for instance the view has nothing to show(as the frame was not set in visible region). The completion block may not called.
Move your call to [myView setHidden:YES] from the animations block to the completion block. I think that will probably help. You can still set the alpha of myView to 0 during the animation block (if you want it to fade out), or before the entire call to -[UIView animateWithDuration:delay:options:animations:completion:] if you want it to disappear right away.
I referred to the DOC and it said:
completion
... This block has no return value and takes a single Boolean argument that indicates whether or not the animations actually finished before the completion handler was called. ...
But I find that no matter you use the bool parameter or not, the completion: block will always execute after animations: block. Just like the two simple block-based animation code snippets shown below, both of them are doing the same.
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationCurveEaseInOut
animations:^{
[myView setAlpha:0.0f];
}
completion:^(BOOL finished) {
[myView removeFromSuperview];
}];
and
[UIView animateWithDuration:0.3f
delay:0.0f
options:UIViewAnimationCurveEaseInOut
animations:^{
[myView setAlpha:0.0f];
}
completion:^(BOOL finished) {
if (finished) [myView removeFromSuperview];
}];
And I find that most people(including me) use the first one(even the apple's official doc example). So,
what's the finished parameter used for here exactly?
or what's the situation will be used?
The finished parameter will be NO when the animation was cancelled: typically, when you have interrupted the animation to start another one (e.g. you have begun a new animation, before the current one has ended, with the parameter to begin from the current state) or you have directly cancelled the animation.
In effect this cancels the current animation, but the completion block is still called. If you were chaining a sequence of animations you would want that chain to stop, so you would only continue the chain of the previous animation had finished.
As an example, imagine you had a game where a bomb was flying across the screen. If the user doesn't tap the bomb, it explodes when it reaches the edge. So you'd have one animation to move the bomb, and your completion block would have another animation to show the explosion, and maybe a call to some method to decrease a score or something.
If the user taps the bomb, you'd cancel the moving animation and have the bomb fly harmlessly away. Your original completion block would still be executed, so you'd need to know if the animation had finished on its own, or been cancelled.
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?
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).