How to know/test when an animation has finished playing - iphone

I am starting an animation via a button press. Here is the code for the button:
-(IBAction)startAnimation:(id)sender{
stick.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"photo 1.JPG"],
[UIImage imageNamed:#"photo 2.JPG"],
[UIImage imageNamed:#"photo 3.JPG"],
[UIImage imageNamed:#"photo 4.JPG"],
[UIImage imageNamed:#"photo 5.JPG"],nil];
[stick setAnimationRepeatCount:200];
stick.animationDuration = 0.5;
[stick startAnimating];
}
and when the animation is done, i want to have a button appear, to play another animation on the screen. How can i test or see when my animation is done playing? Thanks in advance!

You haven't told us what stick is, but it looks like a UIImageView. You can only call isAnimating to check whether the animation is still running but you don't get any notification and there's no delegate either. You can calculate the stop time (200 * 0.5) and thus set up a timer (add a little safety margin). This won't be 100% correct but it might be "good enough".

If you called your animation using blocks, you could use a completion block.
Here is a tutorial you can refer to which shows a couple different ways to call animation routines on iOS. This tutorial also shows what you can do for completion if you don't feel like using blocks (namely UIView's setAnimationDidStopSelector method).

Related

Animating imageview takes time for first time

I am animating the ImageViews then the user taps a button. I have more than 40
images. The code I have used is
arr3 = [[NSArray alloc]initWithObjects:[UIImage imageNamed:#"Aperture_00000.png"],
[UIImage imageNamed:#"Aperture_00001.png"],
[UIImage imageNamed:#"Aperture_00002.png"],
...
[UIImage imageNamed:#"Aperture_00023.png"], nil];
imgv.animationImages = arr3;
imgv.animationDuration=2.0f;
imgv.animationRepeatCount =1;
The method to start the animation is:
-(void)animate {
[imgv startAnimating];
}
But it takes a lot of time when the user presses the button for the first time. What could be the solution for this?
The reason is following code:
arr3 = [[NSArray alloc]initWithObjects:[UIImage imageNamed:#"Aperture_00000"],[UIImage imageNamed:#"Aperture_00001"],[UIImage imageNamed:#"1.png",#"2.png",#"3png",#"4.png",#"5.png",#"6.png",#"7.png",#"8.png",#"9.png",#"10.png",#"11.png",#"12.png",#"13.png",#"14.png",#"15.png",];
What you can do is load this array somewhere else.
Note : This is a very memory consuming way of loading the images. Your app will definitely crash after you visit this class 2-3 times. Instead of this use some alternative. The easiest alternative I can suggest is load a image on UIImageView and change the image periodically. It'll give you animation effect.
I would suggest you rather doing it programmatically you should create animated gif image from the images. Here is online tool you can set speed and other parameters
http://picasion.com/
and use
https://github.com/arturogutierrez/Animated-GIF-iPhone
UIImageView category to display that gif image in that case you can save your CPU time.
Unhide the imageView when you want to play animation and hide when you want to stop.
I would suggest to give that at least a try.

Does UIImageView have a property to indicate setImage has completed and animations are ready?

Just getting started with Obj-C and iOS programming. I have some code that loads and imageView into a (HIDDEN: YES) UIView - simply
[bgImageView setImage:[UIImage imageNamed:#"Filename.jpg"];
The code then sets and commits animations on the fgImageView and the bgImageView.
Because some of the images can be large, occasionally the animation from the new bgImage does not render with the new background image in it and instead 'stalls and displays'. Note that the stall does not happen during setImage. It happens during the second animationCommit later in code. Because animationCommit forces the application to wait until the animation of this ImageView is done.
What I'm looking for is sort of a 'setImage commit' on UIImageView,
I'd much rather display a spinner until the image is loaded, then proceed with the animation, however there doesn't appear to be an isLoaded property for UIImageView class.
Is there a simple way to determine that the UIImageView is done with the setImage call?
My gut is that setImage is handled synchronously, especially since you're talking about how the app stalls. You'd want to run setImage in an NSOperation to allow that happen in the background.
http://developer.apple.com/library/ios/#documentation/cocoa/reference/NSOperation_class/Reference/Reference.html
NSInvocationOperation *myOp = [[NSInvocationOperation alloc] initWithTarget:myImageView selector#selector(setImage:) object:aUIImage];
[myOp addObserver:(NSObject *)self forKeyPath:(NSString *) #"isFinished" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:NULL];
[anOpQueue addOperation:myOp];
You'd then handle the KVO operation and handle removing the spinner there.
[UIImageView setImage:] is not asynchronous: It's done immediately before the message returns. If the view does not show the image instantly it's probably because of some lazy UIImage code. My guess is that [UIImage imageNamed:] just references the file in the bundle and loads it only after the image data is requested.
You could try to force the image to load by sending it a CGImage message:
[bgImageView.image CGImage];
If this still does not trigger the image to be loaded you have to draw it somewhere:
UIGraphicsBeginImageContext((CGSize){1, 1});
[bgImageView drawInRect:(CGRect){{0, 0}, {1, 1}}];
UIGraphicsEndImageContext();
There is a method in UIImageView - (BOOL)isAnimating, so you could potentially use:
if (![bgImageView isAnimating]) {
// continue to next image;
}
Would that suffice or is there other animation in progress that would give false responses?

Flashing UILabel as a

I'm trying to use a UIImage as a button which gives the impression of it being turned on then off again within about half a second. This works fine if I switch it on but if I want to switch it off again it doesn't switch on at all. I have a short loop in there to prevent it switching on and off so fast I can't see it but it doesn't switch on at all. I've tried it with and without the [flashingButton release]. Is there something I'm misunderstanding here? Can I addSubview and removeFromSuperView at the same time even with a short delay?
if ( some conditional statements in here .......) {
UIImage *estimateButton1 = [UIImage imageNamed:#"FlashingButton.png"];
flashingButton = [[UIImageView alloc] initWithImage:flashingButton1];
flashingButton.frame = CGRectMake (146,8,165,30);
[self.view addSubview:flashingButton];
// [flashingButton release];
// short loop in here to delay urning the button off
[self.flashingButton removeFromSuperview];
User interface drawing doesn't happen until later in the main run loop. Your call to addSubview adds flashingButton to self.view but doesn't draw it. Your short loop blocks the main run loop, so it still doesn't get to the drawing part. And then, you remove the button before the main run loop gets to draw it.
A solution is to let the main run loop continue after you've added the flashing button (so it will get drawn), but create a timer that will remove that button in the future. You can use performSelector:withObject:afterDelay: to do this.
[self.flashingButton performSelector:#selector(removeFromSuperview) withObject:nil afterDelay:0.5f];
You can read about run loops in "Threading Programming Guide" and about how drawing gets done in "View Programming Guide for iOS."
Looping within the main thread will just hang the program temporarily and prevent any drawing from taking place. Instead, use an NSTimer.

When does Default.png get erased?

A Default.png in your application directory looks like a good way to get a zoom-in splash screen "for free". Zero LOC and everything happens before your applicationDidFinishLaunching gets called so your app launch feels snappy.
Unfortunately it erases itself a bit earlier than I would like: sometime after applicationDidFinishLaunching, but before I start drawing.
Does anyone know when it happens and I how can convince it to stay longer?
How do you start drawing? I think it goes away the first time the screen is drawn, which seems to be at the end of the first run loop.
You can create the effect of having it stay longer by showing an image view of Default.png. Something like (untested):
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];
imageView.image = [UIImage imageNamed:#"Default.png"];
imageView.tag = 1234; // Must be a unique tag (int)
[window addSubview:imageView];
[imageView release];
//...
// When you want to hide/remove it:
UIView *defaultPng = [window viewWithTag:1234];
[defaultPng removeFromSuperview];
If you want it to be shown for some specific period of time, I imagine you'd use the second part of the code either in an NSTimer action method, or a method called using performSelector:withObject:afterDelay:. If the delay is unknown, you can use that code wherever you like.
Caveat: If your app is multithreaded, make sure it's called from the main thread. You can use performSelectorOnMainThread:withObject:waitUntilDone:.
Hope this helps.

How to pause a UIImageView animation

I have an animation that I'm displaying using a UIImageView:
imageView.animationImages = myImages;
imageView.animationDuration = 3;
[imageView startAnimating];
I know I can stop it using stopAnimating, but what I want is to be able to pause it. The reason is that when you call stop, none of your animation images are displayed, whereas I would like the last one that is up at the time when I hit a button to stay up.
I have tried setting the duration to a much larger number, but that causes all the images to disappear as well. There must be a really basic way to do this?
This code will pause an animated object at its current position in the animation process. If you record other variables like the time or progress or whatever you need, it should be fairly trivial to resume the animation again.
UIView *viewBeingAnimated = //your view that is being animated
viewBeingAnimated.frame = [[viewBeingAnimated.layer presentationLayer] frame];
[viewBeingAnimated.layer removeAllAnimations];
//when user unpauses, create new animation from current position.
Hmmm...since no one seems to know I guess it's not possible.
I went ahead and wrote my own UIView, with a UIImageView subview, that uses an NSTimer to switch between images. The advantage of this is that I can pause and resume the timer at my leisure, and performance doesn't seem to be an issue.
#oddmeter just a little edit:
animatedView.animationImages = images; //images is your array
[animatedView startAnimating];
//Then when you need to pause;
[animatedView stopAnimating]; //Important!!
animatedView.image = [images objectAtIndex: 0];
This should do the trick: https://developer.apple.com/library/ios/#qa/qa2009/qa1673.html
It basically tells you what you need to do to pause/resume any CALayer based animation.
If you feel uncomfortable using CALayer methods on UIImageView controlled animation, you could always just make the UIImage array based animation yourself. The code needed is very short, you can take it from here: http://rssv2.blogspot.com/2011/04/animating-series-of-images-with-calayer.html
Another option is to set the image property as well as the animationImages property. Doing this will display the static image when the UIImageView has its animations stopped.
Assuming your class is a subclass of UIImageView and have an NSMutableArray of images, do the following:
self.animationImages = images;
//yes, I'm skipping the step to check and make sure you have at least one
//element in your array
self.image = [images objectAtIndex: 0];
Maybe you can take a screenshot of the last animated image and display that?