smooth UIImageView animation for multiple images - iphone

I have used animation on an UIImageView to animate 36 images like this:
-(void) kickOffTheAnimation {
self.imgView.animationImages = imagesArr;
[self.imgView setAnimationRepeatCount:HUGE_VALF];
self.imgView.animationDuration =0.9;
[self.imgView startAnimating];
}
and myviewDidLoad method is simply as:
NSMutableArray *imagesArr = [[NSMutableArray alloc] init];
for(int i =0; i<35; i++) {
[imagesArr addObject:[UIImage imageNamed: [NSString stringWithFormat:#"img%i#2x.png",i]]];
}
[self kickOffTheAnimation];
However, there is a small glitch, the animation is not smooth when it reaches the final image and repeats the animation from the first image, how can I fix this problem?
EDIT:
the exact problem is there is a milliseconds hang happens after reaching img35.png and showing img0.png

I have sometimes noticed a very small loop delay with a larger in memory image array. It could be that some resource has to be reloaded. I have used AVPlayer in repeat mode with better luck for a small movie. An actual movie might also compress better.

Related

When animation finishes, keep the ending image of the animation

i have an animation that starts out as a plain back ground. when the animation begins, it plays and when it finishes, the screen goes back to the original background. How can i keep the ending image of my animation and set it as my background? Thanks for the help!!
By the way, what i am asking is similar to a childrens book. When the animation finishes, i want the background to stay the same as the very last part of the animation. So it looks like the animation just stops!
Assuming your NSArray for the images is called imageArray and your UIImageView is called imageView, try this:
imageView.image = [imageArray lastObject];
imageView.animationImages = imageArray;
imageView.animationDuration = 1.0f;
imageView.animationRepeatCount = 1;
[imageView startAnimating];
That should loop through the images once, and then once it ends, leave the UIImageView on the last image. Hope that Helps!

UIImageView Fade In/Out with NSArray

I have an NSArray of images that I want to fade in/out between each other (much like how Flickr handles their home screen).
The problem I'm having is figuring out how to utilize the [UIView beginAnimations]; with the NSArray... any idea?
My code is below.
Thanks in advance!
NSArray *myImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"show_robmachado.jpg"],
[UIImage imageNamed:#"show_losness.jpg"],
[UIImage imageNamed:#"show_blanchard.jpg"],
[UIImage imageNamed:#"show_tonino.jpg"],
nil];
homeAnimation.animationImages = myImages;
homeAnimation.animationRepeatCount = 0; // 0 = loops forever
homeAnimation.animationDuration = 7.0;
[homeAnimation startAnimating];
The array method is really for simple frame-based animations, not for transitions.
Instead I would have two UIImageViews at the same position, and set up a timer that would work through the array, using UIView animations to animate one image view fading to an alpha of 0 and the other to an alpha of 1. Then you'd get a kind of fading switch you are going for.
The .image property on a UIImageView might also be animatable, try in a timed loop changing .image on an image view in a UIView based animation block and see if you get a cross-fade.

how to make growing flower animation between two views

i have a UIButton in a viewcontroller's view, i wrote action method form that i am going to another view controller's view. Now i am trying to implement animation between to views.i tried with many types one of the type animation is shown below
[UIView beginAnimations:#"flipping view" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[self.view addSubview:anotherView];
[UIView commitAnimations];
This animation is working well but i am trying to implement some "growing flower animation"(name may be different) means the other view pop up from the button co-ordinatesand occupy entire screen.my custombutton` co-ordinates are (500,500,20,20).can any one suggest me for implementing this animation.
Thank you.
This can be achieved by various methods.
You can use:-
1 )
Core animations
UIImage class's animations
Cocos 2D
UIAnimation Classes (by simple changing the frames)
..and many more
It actually depends on your requirements, and your comfortable level with these classes/technologies.
If you just want to display growing flower, then the simpler (but not the optimized, and best) solution is to create different images,and put them in array, and then animate it
A similar example is available at: -
Animating images
If you have step by step images of growing flower images, then you can simply implement this. Write a function to implement simple implementation,
NSMutableArray * images;
//allocates the images array.
images = [[NSMutableArray alloc] init];
//loops till the 18images are added into array.
for (int index = 1; index < 19; index++) {
//get the image name.
NSString * imageName = [NSString stringWithFormat:#"Animation%d",index];
//get the path for the image in resourse file.
NSString * path = [[NSBundle mainBundle] pathForResource:imageName ofType:#"png"];
//allocate and own the image object for the particular image.
UIImage *image = [[UIImage alloc] initWithContentsOfFile:path];
//adds it to array.
[images addObject:image];
//release after adding.
[image release];
//remove the useless pointer.
image = nil;
}
//give the pointer to the array holding the images.
imageView.animationImages = images;
//after using it, release it.
[images release];
//remove the useless pointer
images = nil;
//set animation duration
imageView.animationDuration = 3.00;
//start animate
[imageView startAnimating];
After when you want to stop the animation you can simply call
[imageView stopAnimation];
You have another choice of
imageView.repeatCount = 1;
imageView is an instance of uiimageView, allocated one.

Animation one image to the next

I have a flash file and need to reprogram for iPhone.
The design of the app is a navbar with start buttom and an image view below them. I have 46 PNL images that I want to show in succession after the start button is clicked. Each picture will stay on the screen for 5 seconds.
I tried to replicate a code that I got off of YouTube but it did not work.
For the viewcontroller.h I used the following code verbatim and was able to link images (I call them ac) to the image view and also to establish a link for the start button:
{
IBOutlet UIImageView *ac;
}
-(IBAction)startclick:(id)sender;
For the viewcontroller.m I used the following concept but I received many syntax warnings:
NSarray
List of 46 png files using #" notation for string
Last png followed by nil
Then some notation for length that each image appears.
If someone could help me out with the viewcontroller.h and viewcontroller.m to command this sort of animation, it would be much appreciated.
You should use UIImageView's animationImages property to do this, with your button calling startAnimating and/or stopAnimating:
UIImage *frame1 = [UIImage imageNamed:#"frame1.png"];
UIImage *frame2 = [UIImage imageNamed:#"frame2.png"];
UIImage *frame3 = [UIImage imageNamed:#"frame2.png"];
UIImage *frame4 = [UIImage imageNamed:#"frame2.png"];
uiImageView.animationImages = [[NSArray alloc] initWithObjects:frame1, frame2, frame3, frame4, nil];
uiImageView.animationDuration = 1.0 // defaults is number of animation images * 1/30th of a second
uiImageView.animationRepeatCount = 5; // default is 0, which repeats indefinitely
[uiImageView startAnimating];
// [uiImageView stopAnimating];
If you can't work out the syntax of Objective-C, you're going to struggle to do pretty much anything related to iPhone development.

Problem dealloc'ing memory used by UIImageViews with fairly large image in an UIScrollView

I have a large UIScrollView into which I'm placing 3-4 rather large (320x1500 pixels or so) UIImageView image tiles. I'm adding these UIImageViews to the scroll view inside of my NIB files. I have one outlet on my controller, and that is to the UIScrollView. I'm using a property (nonatomic, retain) for this, and sythesizing it.
My question is this: When I observe this in Memory Monitor, I can see that the memory used goes up quite a bit when the view with all these images is loaded (as expected). But when I leave the view, it and its controller are dealloc'd, but do not seem to give up anywhere near the memory they had taken up. When I cut one of these views (there are several in my app) down to just 1-3 images that were 320x460 and left everything else the same, it recaptures the memory just fine.
Is there some issue with using images this large? Am I doing something wrong in this code (pasted below)?
This is a snippet from the viewController that is causing problems.
- (CGFloat)findHeight
{
UIImageView *imageView = nil;
NSArray *subviews = [self.scrollView subviews];
CGFloat maxYLoc = 0;
for (imageView in subviews)
{
if ([imageView isKindOfClass:[UIImageView class]])
{
CGRect frame = imageView.frame;
if ((frame.origin.y + frame.size.height) > maxYLoc) {
maxYLoc = frame.origin.y;
maxYLoc += frame.size.height;
}
}
}
return maxYLoc;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.scrollView setContentSize:CGSizeMake(320, [self findHeight])];
[self.scrollView setCanCancelContentTouches:NO];
self.scrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
self.scrollView.clipsToBounds = YES;
self.scrollView.scrollEnabled = YES;
self.scrollView.pagingEnabled = NO;
}
- (void)dealloc {
NSLog(#"DAY Controller Dealloc'd");
self.scrollView = nil;
[super dealloc];
}
UPDATE: I've noticed another weird phenomenon. If I don't use the scroll on the view, it seems to be hanging on to the memory. But if I scroll around a bunch and ensure that all of the UIImageViews became visible at one point, it will free up and regain most of the memory it lost.
UPDATE2: The reason I'm asking this is my app is actually crashing due to low memory. I wouldn't mind if it were just caching and using up extra memory, but it doesn't seem to ever release it - even in didReceiveMmoryWarning conditions
I've solved the mystery - and I'm pretty sure this is a bug on Apple's side.
As Kendall suggested (thanks!), the problem lies in how InterfaceBuilder loads images from the NIB file. When you initFromNib, all UIImageViews will init with a UIImage using the imageNamed: method of UIImage. This call uses caching for the image. Normally, this is what you want. However, with very large images and additionally ones that scroll far off of the visible area, it does not seem to be obeying memory warnings and dumping this cache. This is what I believe to be a bug on Apple's side (please comment if you agree/disagree - I'd like to submit this if others agree). As I said above, the memory used by these images does seem to be released if a user scrolls around enough to make it all visible.
The workaround that I've found (also Kendall's suggestion) is to leave the image name blank in the NIB file. So you lay out your UIImageView elements as normal, but don't select an image. Then in your viewDidLoad code, you go in and load an image using imageWithContentsOfFile: instead. This method does NOT cache the image, and therefore does not cause any memory issues with retaining large images.
Of course, imageNamed: is a lot easier to use, because it defaults to anything in the bundle, rather than having to find the path. However, you can get the path to the bundle with the following:
NSString *fullpath = [[[NSBundle mainBundle] bundlePath];
Putting that all together, here's what that looks like in code:
NSString *fullpath = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:[NSString stringWithFormat:#"/%#-%d.png", self.nibName, imageView.tag]];
UIImage *loadImage = [UIImage imageWithContentsOfFile:fullpath];
imageView.image = loadImage;
So adding that to my code above, the full function looks like this:
- (CGFloat)findHeight
{
UIImageView *imageView = nil;
NSArray *subviews = [self.scrollView subviews];
CGFloat maxYLoc = 0;
for (imageView in subviews)
{
if ([imageView isKindOfClass:[UIImageView class]])
{
CGRect frame = imageView.frame;
if ((frame.origin.y + frame.size.height) > maxYLoc) {
maxYLoc = frame.origin.y;
maxYLoc += frame.size.height;
}
NSString *fullpath = [[[NSBundle mainBundle] bundlePath] stringByAppendingString:[NSString stringWithFormat:#"/%#-%d.png", self.nibName, imageView.tag]];
NSLog(fullpath);
UIImage *loadImage = [UIImage imageWithContentsOfFile:fullpath];
imageView.image = loadImage;
}
}
return maxYLoc;
}
Separate from your imageNamed caching issues, the answer to your question
I have a large UIScrollView into which
I'm placing 3-4 rather large (320x1500
pixels or so) UIImageView image tiles.
[...] Is there some issue with using
images this large?
Is in the header of the UIImage docs:
You should avoid creating UIImage objects that are greater than 1024 x 1024 in size.
Besides the large amount of memory such an image would consume, you may run into
problems when using the image as a texture in OpenGL ES or when drawing the image
to a view or layer.
Also, Apple claims to have fixed the imageNamed cache-flushing problem in 3.0 and beyond, although I've not tested this extensively, myself.
It could be the system caching references to your images in memory, assuming you have just drug in the images from the media browser in IB the code underneath is probably using the UIImage imageNamed: method...
You could try loading all the images with imageWithContentsOfFile: , or imageWithData: and see if it behaves the same (dragging in unfilled UIImageViews in IB and setting contents in viewDidLoad:).
Read the UIImage class reference if you'd like a little more detail, it also describes which methods are cached.
If it's the cache it's probably OK though as the system would free it if needed (did you also try hitting the Simulate Memory Warning in the simulator?)
Completing the answer of Bdebeez.
One nice idea is to override the imageNamed: calling the imageWithContentsOfFile:.
Here is the idea of the code:
#implementation UIImage(imageNamed_Hack)
+ (UIImage *)imageNamed:(NSString *)name {
return [UIImage imageWithContentsOfFile:[NSString stringWithFormat:#"%#/%#", [[NSBundle mainBundle] bundlePath], name ] ];
}
#end
Note: With this override you will not have any cache loading UIImages, if you need this, you will have to implement your own cache.
- (void)dealloc {
NSLog(#"DAY Controller Dealloc'd");
[self.scrollView release];
[super dealloc];
}
give that a shot, your #property() definition is requesting it to be retained, but you weren't explicitly releasing the object
From what I learned on its memory management behavior is that views won't get dealloc unless low in memory. Try an official demo like SQLBooks: 1. Run with Leaks Monitor 2. Run through every views it has. 3. Go back to the root view. 4. You will notice the memory usage level is still the same. As Kendall said it may be cached?
I think you shouldn't pay attention on this memory usage pattern -- because when the new images are pointed to the UIScrollView, the old image objects will be released and memory will be freed for new images anyway.
There is a known problem - a memory leak in imageName. I found a really useful solution for it - creating image cash in application delegate, this way optimizing the performance and memory usage in my application.
See this blog post