UIImageView+animatedGIF always LOOPS - ios

I used class made by "mayoff" (Rob Mayoff) "UIImageView+animatedGIF" which was proposed in one of the answers here on stackoverflow. UIImageView+animatedGIF
With it I can import animated .gif images in UIImageView on iOS. This class works flawlessly, but the only problem is that .gif is always looping. No matter how I export it (I am exporting image from photoshop - 67 frames, set repeat to "once") it loops forever in UIImageView.
I am importing my .gif with these two lines:
NSURL *url = [[NSBundle mainBundle] URLForResource:#"Loading" withExtension:#"gif"];
self.loadingImageView.image = [UIImage animatedImageWithAnimatedGIFData:[NSData dataWithContentsOfURL:url]];
very simple and it works.
I have tried setting animationRepeatCount property to 1, as recomended by Rob but that didn't do the trick. Also I have tried setting the UIImageView's animationImages property to
gifImage.images too, instead of just setting the view's image property
to gifImage. In that case, .gif is not animating at all.
Any ideas how to play that .gif only once? I can think of many tricks (like setting last frame of the gif to show up after some time but I'd first try something simpler if possible).

I took the test app from that project and changed the viewDidLoad method to this:
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *url = [[NSBundle mainBundle] URLForResource:#"test" withExtension:#"gif"];
UIImage *testImage = [UIImage animatedImageWithAnimatedGIFData:[NSData dataWithContentsOfURL:url]];
self.dataImageView.animationImages = testImage.images;
self.dataImageView.animationDuration = testImage.duration;
self.dataImageView.animationRepeatCount = 1;
self.dataImageView.image = testImage.images.lastObject;
[self.dataImageView startAnimating];
}
When the app launches, it animates the image once and then shows just the last frame. If I connect a button that sends [self.dataImageView startAnimating], then tapping the button runs the animation one more time, then stops again on the last frame.
Make sure you're setting your image view up the way I do above. Make sure you are not setting the image view's image property to the animated image. The image view's image property must be set to a non-animated image if you want the animation to stop.

I have forked "uiimage-from-animated-gif" made by "Dreddik" and added a delegate method
#pragma mark - AnimatedGifDelegate
- (void)animationWillRepeat:(AnimatedGif *)animatedGif
{
NSLog(#"animationWillRepeat");
//[animatedGif stop];
}
So you know the time when animation will repeat and do your own thing in middle of every repetition. You may count the number of times animation repeated and stop animation at a certain number reached.
The forked repository is at https://github.com/rishi420/Animated-GIF-iPhone

Was having issues in start/stp animation & managing animation count
So used this pod
imageViewObject.animate(withGIFNamed: "gif_name", loopCount: 1) {
print("animating image")
}
To start/stop animation :
imageViewObject.isAnimatingGIF ? imageViewObject.stopAnimatingGIF() : imageViewObject.startAnimatingGIF()

Related

Selecting image during Animation

I have an outlet called myImage for an imageView that is set up with an animation of 5 images. With a Tap Gesture Recognizer on it, I want to have the users tap on the correct image as it quickly passes to move onto the next level.
There is an error in my code and this does not work:
- (void)viewDidLoad {
[super viewDidLoad];
self.myImage.animationImages =
[NSArray arrayWithObjects:
[UIImage imageNamed:#"examplePic1.png"],
[UIImage imageNamed:#"examplePic2.png"],
[UIImage imageNamed:#"correctPic.png"],
[UIImage imageNamed:#"examplePic4.png"],
[UIImage imageNamed:#"examplePic5.png"],
nil];
[self.myImage setAnimationRepeatCount:0];
self.myImage.animationDuration = 1;
[self.myImage startAnimating];
}
- (IBAction)TapGestureRecognizer:(id)sender {
if (self.myImage.image = [UIImage imageNamed:#"correctPic.png"]) {
// Launch next level
}
else {
// Vibrate Device and subtract points from score
}
}
You have a fundamental misconception in your code about objects and equality. I assume that you meant "==" in your TapGestureRecognizer method. However, even if you changed the = to == would not give you what you want.
The expressions like
[UIImage imageNamed:#"examplePic1.png"]
call a class method of UIImage that creates a new UIImage object. You have created 5 of these objects, put them into an array, an set the animationImage array of your UIImage object to these images. These objects are all different objects from myView.image: I can tell because I can see from your code that you have assigned 5 new objects to the animationObjects array. Your == test cannot ever work because you are comparing self.image to a brand new UIImage object.
What you are trying to do is determine which image the user touched. There is no method in UIImageView that tells you which animation UIImage is currently showing. You are assuming that the image property of the view will be changed as the animation images are displayed, but there is no reason for this assumption to be true: it is certainly not stated in the documentation. Even if you corrected your code (by doing something like this):
if(self.image == [self.animationImages objectAtIndex:2]){
}
your code would not be correct.
If I were trying to do what you want, I would create a UIView with 5 UIImageView as subview, each with their own gesture recognizer. I would use the frame property of each subview to do my animation.
Looks like the options are to determine which image "should" be showing based upon the startTime of the animation.
Determine which of its animationImages a UIImageView is displaying?
Or, just use a timer to set the currently displayed image.
Detect which image was clicked in UIImageView with animationImages

UIimageView masks into a diamond

Running into a super weird bug in my iOS application I cannot figure out.
I load a UIImageView for a user in my iOS application and then round it into a circle.
- (void)viewDidLoad {
[super viewDidLoad];
self.profileImage.file = [[self.profileObject objectForKey:#"UserID"] valueForKey:#"ProfilePhoto"];
[self.profileImage loadInBackground:^(UIImage *image, NSError *error) {
self.profileImage.image = image;
self.profileImage.layer.cornerRadius = self.profileImage.frame.size.width / 2;
self.profileImage.layer.masksToBounds = YES;
self.profileImage.contentMode = UIViewContentModeScaleAspectFill;
}];
}
This runs perfectly, until I dismiss that view and go back into it a few moments later.
- (void)dismissView {
[self dismissViewControllerAnimated:YES completion:nil];
self.profileImage.image = nil;
}
When I go back into the view, the image rounds from the point it was already rounded prior. Which means it then turns into somewhat of a diamond. See here: http://cl.ly/image/3p1P0M0M1d2H
Any ideas on why this would be happenig?
Workaround
I found that if I load the image in viewDidLoad and round it in viewDidAppear it works just fine. But that seems to "hacky" and doesn't load everything at the same time properly.
Any ideas on what I should try?
The problem is that you're loading the image using sone background threading technique, and the first time you do so, it has to presumably fetch the image from somewhere, the second time it presumably has a cached version so it can run the completion block immediately.
Why should this matter?
At viewDidLoad, under Autolayout, your image view's frame will be zero, yet you're using it to round the corners.
On the first run, the delay in loading the image is enough for the view to have performed a layout pass, so it can round properly. On the second run, it hasn't (because the image is cached), so it can't.
The solution, as you've already discovered, is to set the corner radius when layout has happened - either in viewDidLayoutSubviews or viewDidAppear. Setting the radius can be totally separate to loading the image, and isn't "hacky" at all.
A better solution would be to write an image view subclass that performed it's own corner rounding on layoutSubviews. It's not really the view controller's job to do that rounding.
try changing
self.profileImage.layer.cornerRadius = self.profileImage.frame.size.width / 2;
to
self.profileImage.layer.cornerRadius = self.profileImage.bounds.size.width / 2;
in general it is always better to work internally with bounds rather than frame rect, because this is the internal perspective. self.bounds will reflect autoresizing, auto layout, rotation, scaling and other geometry issues which self.frame will not. Good luck

Morphing with CoreAnimation

I am creating an Navigation Button. When user presses it, the image of the button should change, reflecting it's state (e.g. menu opened / closed). I decided to do a morphing-liek animation for this. Is it possible to implement with CoreAnimation? What animation type do I need to use?
I attached the picture to clearly illustrate what I want. Also, you might see these animations in "Pimp My Ride" show.
You can use animationImages property of UIImageView for this, like this:
myImageView = [[UIImageView alloc] initWithFrame:myImageViewbounds];
//Add images which will be used for the animation using an array. These should exist in your project and bundle already.
myImageView.animationImages = #[[UIImage imageNamed:#"1.png"], [UIImage imageNamed:#"2.png"],[UIImage imageNamed:#"3.png"], [UIImage imageNamed:#"4.png"],[UIImage imageNamed:#"5.png"]];
//Set the duration of the entire animation
myImageView.animationDuration = 0.5;
//Set the repeat count. If you don't set that value, by default will be a loop (infinite)
myImageView.animationRepeatCount = 1;
//Start the animation
[myImageView startAnimating];
To ensure smooth morphing like transition you may check out GPUImage which has many great blur filters. Ideally you should be able to wrap a blur animation between two image animations to achieve what you want.

Can't update a UIImageView properly

I call this method in my ViewController, which contains a UIScrollView, when the user taps a button.
-(void) updateView:(NSURL *) urlPicture{
UIImageView *imageNews = [[UIImageView alloc]initWithFrame:CGRectMake(0,0,300,200)];
imageNews.contentMode = UIViewContentModeScaleAspectFit;
[imageNews setImageWithURL:urlPicture];
[self.scrollView addSubview:imageNews];
}
It seems to work fine, but when I got a strange behavior.
It doesn't clear the previous image to put the new one.
E.g: if the first image is 300x200 and the second one is 200x200 I still can see the sides of the first one when the app download the second.
I would like to know how to clear the previous image before download the second.
I already try imageNews.image = nil; but it didn't work
First you need to remove old view from scrollView. You can edit your code as mentioned below
#define IMAGE_VIEW_TAG 1001
-(void) updateView:(NSURL *) urlPicture{
UIView *oldView = [self.scrollView viewWithTag:IMAGE_VIEW_TAG];
if(oldView)
[oldView removeFromSuperView]
UIImageView *imageNews = [[UIImageView alloc]initWithFrame:CGRectMake(0,0,300,200)];
imageNews.tag = IMAGE_VIEW_TAG;
imageNews.contentMode = UIViewContentModeScaleAspectFit;
[imageNews setImageWithURL:urlPicture];
[self.scrollView addSubview:imageNews];
}
Well I am not really sure what your application does ,
but seems like you need to have only 1 image
so I would suggest you to remove the previous image.
There are 2 ways to do so:
1) you could use your image as property and simply call [_imageNews removeFromSuperView];
2) you can iterate through your self.scrollView's sub views and remove it from there.

UIImageView set to imageWithData ignores contentMode

In my custom tableViewCell, I have an imageView (not the tableViewCell's default imageView) which fills the entire cell. It is set up in IB (and by code) with the contentMode UIViewContentModeAspectFill, and it clips to bounds. Whenever I change the imageView's image to an image loaded with [UIImage imageNamed:...], it resizes and fits the imageView as wished and expected. However, when the image set is loaded with [UIImage imageWithData:...], the image is set, but not resized.
The code that loads the image with data itself is run in a background thread, and looks like this:
- (void)getImage:(NSString *)URL {
NSError *error = nil;
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:URL] options:NSDataReadingMapped error:&error]];
if (!error){
[self.thumbView setImage:image];
[self.thumbView setContentMode:UIViewContentModeScaleAspectFill];
}
}
I have tried setting the image on the main thread, in layoutSubviews, but it always produces the same result – it doesn't resize to fill the imageView. I added the image (JPG) to the app bundle and set it programmatically with [UIImage imageNamed:...], which works, but the app has to get the data from a URL.
I also tried using the UIImageView+AFNetworking-class to set the image async instead of making my own thread, but that doesn't work either.
Why isn't the image respecting the UIImageView's contentMode when it's loaded from data? Any help is appreciated. Neither JPEGs nor PNGs are working.
If anyone else stumbles upon the same issue, here's what I did to fix it.
I made a new imageView in IB, removed the old one, and only changed the contentMode-value and clipsToBounds-value. In the tableViewCell.m init-code, I set the placeholder image, and voila – everything works like a charm.
Although I don't really know what caused it, it may have been the Clears Graphics Content checkmark's fault for being set (oops).

Resources