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?
Related
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.
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).
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?
What is the best or recommended technique for animating PNG Sequences.
Heres what I've learned:
Do it Manually
Using MutableArrays containing Strings, you can animate a UIImageView with a timer which increments an index number
UIImage - animation methods
This works, the only problem is to find if an image has completed its animation, you have to check the isAnimating BOOL, and to do that you need a timer.
What is the best and recommended?
Looking to do Oldschool game sprite animations,
ie:
Idle Animation
Attack Animation
Walk Animation
ect...
Let me know if any one has something.
#lessfame
Example to animate arrows
UIImage* img1 = [UIImage imageNamed:#"fleche1.png"];
UIImage* img2 = [UIImage imageNamed:#"fleche2.png"];
NSArray *images = [NSArray arrayWithObjects:img1,img2, nil];
UIImageView* imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 160.0, 160.0)];
[imageView setAnimationImages:images];
[imageView setAnimationRepeatCount:100];
[imageView setAnimationDuration:3.0];
imageView.center = myView.center;
[imageView startAnimating];
[myView addSubview:imageView];
[imageView release];
Easiest way is to use Core Animation layers to do sprite animation:
Make a 'multi-cell' image strip (could be PNG or JPG) of all the various moves for the sprite. Make each 'cell' be a fixed height or width.
Put the image in a UIImageView.
Take the CALayer of the view, and adjust the contentsRect property of the layer. This acts as a clipping rectangle for the sprite. To animate sprite all you have to do is move the contentsRect over to the next cell position in the image strip.
Something like this will do it (assuming you've already calculated the newSpritePosition.
[CATransaction begin];
[CATransaction setDisableActions:YES];
spriteLayer.contentsRect = newSpritePosition;
[CATransaction commit];
(If you don't do the second line, then you'll get a default slide animation instead of a 'jump' to the next state.)
With this technique you can rotate through all the frames of the sprite -- much like a flipbook. CALAyer transactions are optimized so you should get pretty fast frame rates. You can set an animationDidStop completion handler to move to the next state of the sprite or loop back to the beginning frame.
It depends on how you are going to use the sprites. If you just need a simple looping sprite then the UIImage method is great. If you want more granular control then you will be happier loading the images into an array and cycling them using a NSTimer to handle the timing. Personally I use the array method most often because it leaves me more options in the future (like detecting when animations have completed). One more suggestion would be to check out the cocos2d project. Its sprite is alot more powerful than either of these suggestions.
As I said in another answer, I found this to be a good way: PNG Animation method by Moses DeJong
From his words:
This example implements an animation oriented view controller that simply waits to read the PNG image data for a frame until it is needed. Instead of alllocating many megabytes, this class run in about a half a meg of memory with about a 5-10% CPU utilization on a 2nd gen iPhone.
I'm still unsure exactly how it's done. I believe it basically uses UIImageView to cache up AVAudioPlayer.
Im having a bit of trouble right now adding the same image multiple times and removing it all at one time after the gamelooop.
I manage to add the image by creating 1 UIImageview for every image but i know thats its not the practical way memory wise since im allocating a lot of uiimageview with the same image.
I use this code to load the image:
UIImageView *imgView1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"correct.png"]];
UIImageView *imgViewn = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"correct.png"]];
CGRect imgRect = CGRectMake((touch.x-20), (touch.y-20), 40, 40);
[imgView1 drawInRect:imgRect];
[imgViewn drawInRect:imgRect];
[imgView1 release]
[imgViewn release]
Basically i use this to add image base on the location of the usertouch made on the subview (with image). If the users set of touches are correct this is where the game loops and show another image for the user to touch.
But after the new image load the "correct.png" image which is added on the previous touch is still on view.
Can someone show me a correct way to do this coz im kinda new to programming but i know that im gonna have a memory problem later if i keep on allocating image every time a user touch the screen.
Thanks in advance.
If you're trying to merely move an image (or series of images) through each run of the gameloop, rather than creating and removing them all each time, perhaps create the series of N images only once.
When the touches or gameloop begins, draw the images in the rectangles you're calculating from the touch event, and then when the loop is over, set the hidden property on the object to YES or NO (not sure exactly what your objective is).
It's hard to give you code without more details on what you're doing, but the basic idea is this:
When you first start the program/view, create your N images, and set imageView.hidden = YES;
On each loop, call the [imageView drawInRect:imgRect] method for each image, and set imageView.hidden = NO;.
When the view/program is done, call the [imageView release] method on each object.