How to recognize particular image is animating during imageview animation? - ios

I am creating a timer which is used to play a song for 6 seconds.But i want that whenever i clicked the button it will recognized the particular image which is animating at that particular instant.For that i used CALayer but it is not giving the image name.
This is my code:
-(void)playSong
{
timerButton.imageView.animationImages =[NSArray arrayWithObjects:[UIImage imageNamed:#"Timer6.png"],[UIImage imageNamed:#"Timer5.png"],
[UIImage imageNamed:#"Timer4.png"],[UIImage imageNamed:#"Timer3.png"],
[UIImage imageNamed:#"Timer2.png"],[UIImage imageNamed:#"Timer1.png"],
nil];
timerButton.imageView.animationDuration=6.0;
[self.player play];
[timerButton.imageView startAnimating];
}
- (void)handleLongPressGestures:(UILongPressGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateBegan)
{
CALayer *player1 = timerButton.imageView.layer;
}
}
Please help me.

Unfortunately, you cannot get the image name from a UIImageView or UIImage object.
You could, however, set an accessibility identifier to a UIImage object that, in your case, could be it's file name.
Then simply doing someUIImageObject.accessibilityIdentifier should return the file name.
(refer answer)
Example:
UIImage *image = [UIImage imageNamed:#"someImage.png"];
[image setAccessibilityIdentifier:#"someImage"];
NSLog(#"%#",image.accessibilityIdentifier);
Now... you'd expect timerButton.imageView.image.accessibilityIdentifier to give you the image name but that's not how it works when the UIImageView is animating.
This time, we need to access it via the UIImageViews animationImages array property.
For this, we will need some custom logic to get the UIImage object from this animationImages array.
We'll first record the time we started animating the images and with some basic maths, we can calculate the index of the animationImages array that is currently being displayed in the UIImageView.
(refer answer)
Answer (code):
-(void)playSong
{
NSMutableArray *arrImages = [[NSMutableArray alloc] init];
for(int i = 6 ; i > 0 ; i--) {
//Generate image file names: "Timer6.png", "Timer5.png", ..., "Timer1.png"
NSString *strImageName = [NSString stringWithFormat:#"Timer%d.png",i];
//create image object
UIImage *image = [UIImage imageNamed:strImageName];
//remember image object's filename
[image setAccessibilityIdentifier:strImageName];
[arrImages addObject:image];
}
[timerButton.imageView setAnimationImages:arrImages];
[timerButton.imageView setAnimationDuration:6.0f];
[timerButton.imageView setAnimationRepeatCount:0];
[self.player play];
[timerButton.imageView startAnimating];
//record start time
startDate = [NSDate date]; //declare "NSDate *startDate;" globally
}
- (void)handleLongPressGestures:(UILongPressGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateBegan) {
[self checkCurrentImage];
}
}
-(void)checkCurrentImage
{
//logic to determine which image is being displayed from the animationImages array
NSTimeInterval durationElapsed = -1 * [startDate timeIntervalSinceNow];
NSTimeInterval durationPerFrame = timerButton.imageView.animationDuration / timerButton.imageView.animationImages.count;
int currentIndex = (int)(durationElapsed / durationPerFrame) % timerButton.imageView.animationImages.count;
UIImage *imageCurrent = timerButton.imageView.animationImages[currentIndex];
NSString *strCurrentImage = imageCurrent.accessibilityIdentifier;
NSLog(#"%#",strCurrentImage);
}

Related

ios imageview animation using array causes semaphore_wait_trap

I'm trying to animate an imageview by providing it with an array of images. These images have been extracted from a spritesheet having lots of images one after the other.
Here is my code:
-(NSMutableArray*)getIndividualImagesFromImage:(UIImage*)collectionOfEmoticonImages
{
NSMutableArray *imagesArray = [[NSMutableArray alloc] init];
//Let's find out the total number of images in this big image
int totalEmoticonImages = collectionOfEmoticonImages.size.width/WIDTH_HEIGHT_OF_EMOTICONS;
for(int emoticonIndex = 0; emoticonIndex < totalEmoticonImages; emoticonIndex++)
{
//crop the image at each index and put smaller images in the array
UIImage *croppedImage = [[UIImage alloc] init];
croppedImage = [self cropImage:collectionOfEmoticonImages atIndex:emoticonIndex];
[imagesArray addObject:croppedImage];
}
return imagesArray;
}
-(void)getEmoticonImageViewAnimating:(NSInteger)index
{
imagesArray = [self getIndividualImagesFromImage:[emoticonsPNGImages objectAtIndex:index]];
//Animate using the images in imagesArray
emoImageView.animationImages = [NSArray arrayWithArray:imagesArray];
emoImageView.animationDuration = 2;
emoImageView.animationRepeatCount = 1;
[emoImageView startAnimating];
[self performSelector:#selector(animationDidFinish) withObject:nil
afterDelay:emoImageView.animationDuration];
}
Everything works fine if I comment [emoImageView startAnimating]; line. But with this statement, animation works fine for 6 times but then I get a semaphore_wait_trap on trying to run it 7th time.
Any pointers?

Image auto-rotates after using CIFilter

I am writing an app that lets users take a picture and then edit it. I am working on implementing tools with UISliders for brightness/contrast/saturation and am using the Core Image Filter class to do so. When I open the app, I can take a picture and display it correctly. However, if I choose to edit a picture, and then use any of the described slider tools, the image will rotate counterclockwise 90 degrees. Here's the code in question:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationItem.hidesBackButton = YES; //hide default nav
//get image to display
DBConnector *dbconnector = [[DBConnector alloc] init];
album.moments = [dbconnector getMomentsForAlbum:album.title];
Moment *mmt = [album.moments firstObject];
_imageView.image = [mmt.moment firstObject];
CGImageRef aCGImage = _imageView.image.CGImage;
CIImage *aCIImage = [CIImage imageWithCGImage:aCGImage];
_editor = [CIFilter filterWithName:#"CIColorControls" keysAndValues:#"inputImage", aCIImage, nil];
_context = [CIContext contextWithOptions: nil];
[self startEditControllerFromViewController:self];
}
//cancel and finish buttons
- (BOOL) startEditControllerFromViewController: (UIViewController*) controller {
[_cancelEdit addTarget:self action:#selector(cancelEdit:) forControlEvents:UIControlEventTouchUpInside];
[_finishEdit addTarget:self action:#selector(finishEdit:) forControlEvents:UIControlEventTouchUpInside];
return YES;
}
//adjust brightness
- (IBAction)brightnessSlider:(UISlider *)sender {
[_editor setValue:[NSNumber numberWithFloat:_brightnessSlider.value] forKey: #"inputBrightness"];
CGImageRef cgiimg = [_context createCGImage:_editor.outputImage fromRect:_editor.outputImage.extent];
_imageView.image = [UIImage imageWithCGImage: cgiimg];
CGImageRelease(cgiimg);
}
I believe that the problem stems from the brightnessSlider method, based on breakpoints that I've placed. Is there a way to stop the auto-rotating of my photo? If not, how can I rotate it back to the normal orientation?
Mere minutes after posting, I figured out the answer to my own question. Go figure. Anyway, I simply changed the slider method to the following:
- (IBAction)brightnessSlider:(UISlider *)sender {
[_editor setValue:[NSNumber numberWithFloat:_brightnessSlider.value] forKey: #"inputBrightness"];
CGImageRef cgiimg = [_context createCGImage:_editor.outputImage fromRect:_editor.outputImage.extent];
UIImageOrientation originalOrientation = _imageView.image.imageOrientation;
CGFloat originalScale = _imageView.image.scale;
_imageView.image = [UIImage imageWithCGImage: cgiimg scale:originalScale orientation:originalOrientation];
CGImageRelease(cgiimg);
}
This simply records the original orientation and scale of the image, and re-sets them when the data is converted back to a UIImage. Hope this helps someone else!

Retrieve the name of the UIImage at a specific point in a UIScrollView

I'm having trouble getting my head around this; I've looked around for answers on here but either nothing directly applies to my question or I just can't make sense of it. (I am relatively new to this, so apologise if there is an obvious answer.)
I am inserting an array of UIImages (contained within a UIImageView) into a UIScrollView. I can programmatically scroll to points in the ScrollView, but I need to be able to identify by name which image is currently being shown after scrolling (so I can compare the image to one in another ScrollView).
How I have created my arrays and added the images to the ImageView and ScrollView is below.
ViewController.m
-(void)viewDidLoad {
...
// Store the names as strings
stringArr = [[NSMutableArray arrayWithObjects:
#"img0",
#"img1",
#"img2",
#"img3",
nil] retain];
// Add images to array
dataArr = [[NSMutableArray arrayWithObjects:
[UIImage imageNamed:[stringArr objectAtIndex:0]],
[UIImage imageNamed:[stringArr objectAtIndex:1]],
[UIImage imageNamed:[stringArr objectAtIndex:2]],
[UIImage imageNamed:[stringArr objectAtIndex:3]],
nil] retain];
// Use a dictionary to try and make it possible to retrieve an image by name
dataDictionary = [NSMutableDictionary dictionaryWithObjects:dataArr forKeys:stringArr];
i = 0;
currentY = 0.0f;
// Set up contents of scrollview
// I'm adding each of the four images four times, in a random order
for (imageCount = 0; imageCount < 4; imageCount++) {
// Add images from the array to image views inside the scroll view.
for (UIImage *image in reelDictionary)
{
int rand = arc4random_uniform(4);
UIImage *images = [dataArr objectAtIndex:rand];
imgView = [[UIImageView alloc] initWithImage:images];
imgView.contentMode = UIViewContentModeScaleAspectFit;
imgView.clipsToBounds = YES;
// I have tried to use this to tag each individual image
imgView.tag = i;
i++;
CGRect rect = imgView.frame;
rect.origin.y = currentY;
imgView.frame = rect;
currentY += imgView.frame.size.height;
[scrollReel1 addSubview:reel1_imgView];
[reel1_imgView release];
}
}
scrollReel.contentSize = CGSizeMake(100, currentY);
[self.view addSubview:scrollReel];
...
}
This is how I am working out where I am in the ScrollView (currentOffset), and also exactly which image I need to retrieve (symbolNo). The value of symbolNo is correct when I test it, but I am unsure how to use the value with respect to image name retrieval.
NSInteger currentOffset = scrollReel.contentOffset.y;
NSInteger symbolNo = (currentOffset / 100) + 1;
Thanks in advance for any assistance.
There is no way to do this. The UIImage object doesn't store its name once it's loaded.
You could get around this by using the tag property on the image views if all your images have numerical names.
Otherwise you'll need to find a new way to model your data.
You basically need the reverse mapping of what you had. Here is a quick and dirty solution
NSMutableDictionary *indexToImageMap = [NSMutableDictionary new];
for (imageCount = 0; imageCount < 4; imageCount++) {
// Add images from the array to image views inside the scroll view.
for (UIImage *image in reelDictionary)
{
int rand = arc4random_uniform(4);
UIImage *images = [dataArr objectAtIndex:rand];
imgView = [[UIImageView alloc] initWithImage:images];
imgView.contentMode = UIViewContentModeScaleAspectFit;
imgView.clipsToBounds = YES;
// I have tried to use this to tag each individual image
imgView.tag = i;
i++;
[indexToImageMap setObject:imgView forKey:[NSNumber numberWithInt:i];
CGRect rect = imgView.frame;
rect.origin.y = currentY;
imgView.frame = rect;
currentY += imgView.frame.size.height;
[scrollReel1 addSubview:reel1_imgView];
[reel1_imgView release];
}
}
And to look it up you do
NSInteger currentOffset = scrollReel.contentOffset.y;
NSInteger symbolNo = (currentOffset / 100) + 1;
NSImage *image = [indexToImageMap objectForKey:[NSNumber numberWithInt:symbolNo]];
Subclass image view and add imageName property. if i understand what you are asking this should work.
#import <UIKit/UIKit.h>
#interface myImageView : UIImageView
{
__strong NSString *imageName;
}
#property (strong) NSString *imageName;
#end
#import "myImageView.h"
#implementation myImageView
#synthesize imageName;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
#end
then use a dictionary to keep everything instead of array + dictionary.
myImageView *imgView1 = [[myImageView alloc] init];
[imgView1 setImageName:#"image_name_here"];
[imgView1 setImage:[UIImage imageNamed:#"image_name_here"]];
NSMutableDictionary *dicti = [[NSMutableDictionary alloc] init];
[dicti setObject:imgView1 forKey:#"image_name_here_1"];
[dicti setObject:imgView2 forKey:#"image_name_here_2"];
[dicti setObject:imgView... forKey:#"image_name_here_..."];
when you find the imageView you can search image in dictionary. because you know name of the imageView now.

UIImage Flip Image Direction

For a certain UIImageView animationImages, I wish to create 2 arrays - one per each direction.
I have png files I can load into one of the directions, and I wish to flip each image and add it to second direction array.
I tried to do something like this:
_movingLeftImages = [NSMutableArray array];
_movingRightImages = [NSMutableArray array];
int imagesCounter = 0;
while (imagesCounter <= 8)
{
NSString* imageName = [NSString stringWithFormat:#"movingImg-%i", imagesCounter];
UIImage* moveLeftImage = [UIImage imageNamed:imageName];
[_movingLeftImages addObject:moveLeftImage];
UIImage* moveRightImage = [UIImage imageWithCGImage:moveLeftImage.CGImage scale:moveLeftImage.scale orientation:UIImageOrientationUpMirrored];
[_movingRightImages addObject:moveRightImage];
imagesCounter++;
}
Upon the relevant event, I load the UIImageView animationImages with the relevant array; like this:
if ( /*should move LEFT event*/ )
{
movingImageView.animationImages = [NSArray arrayWithArray:_movingLeftImages];
}
if ( /*should move RIGHT event*/ )
{
movingImageView.animationImages = [NSArray arrayWithArray:_movingRightImages];
}
The images are not flipped. They remain as they where.
Any idea how to handle this?
use this code for animating images
UIImageView * animatedImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200,200)];
NSArray *imageNames = #[#"bird1.png", #"bird2.png"];
animTime =.0;
[animatedImageView setAnimationImages:imageNames] ;
animatedImageView.animationDuration = animTime;
animatedImageView.animationRepeatCount = 1;
[self.view addSubview: animatedImageView];
[animatedImageView startAnimating];

Can the new tintColor property of UIImageview in iOS 7 be used for animating images?

tintColor is a life saver, it takes app theming to a whole new (easy) level.
//the life saving bit is the new UIImageRenderingModeAlwaysTemplate mode of UIImage
UIImage *templateImage = [[UIImage imageNamed:#"myTemplateImage"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
imageView.image = templateImage;
//set the desired tintColor
imageView.tintColor = color;
The above code will "paint" the image's non-transparent parts according to the UIImageview's tint color which is oh so cool.No need for core graphics for something simple like that.
The problem I face is with animations.
Continuing from the above code:
//The array with the names of the images we want to animate
NSArray *imageNames = #[#"1",#"2"#"3"#"4"#"5"];
//The array with the actual images
NSMutableArray *images = [NSMutableArray new];
for (int i = 0; i < imageNames.count; i++)
{
[images addObject:[[UIImage imageNamed:[imageNames objectAtIndex:i]] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
}
//We set the animation images of the UIImageView to the images in the array
imageView.animationImages = images;
//and start animating the animation
[imageView startAnimating];
The animation is performed correctly but the images use their original color (i.e. the color used in the gfx editing application) instead of the UIImageView's tintColor.
I am about to try to perform the animation myself (by doing something a little bit over the top like looping through the images and setting the UIImageView's image property with a NSTimer delay so that the human eye can catch it).
Before doing that I'd like to ask if the tintColor property of UIImageView is supposed to support what I'm trying to do with it i.e use it for animations.
Thanks.
Rather than animate the images myself, I decided to render the individual frames using a tint color and then let UIImage do the animation. I created a category on UIImage with the following methods:
+ (instancetype)animatedImageNamed:(NSString *)name tintColor:(UIColor *)tintColor duration:(NSTimeInterval)duration
{
NSMutableArray *images = [[NSMutableArray alloc] init];
short index = 0;
while ( index <= 1024 )
{
NSString *imageName = [NSString stringWithFormat:#"%#%d", name, index++];
UIImage *image = [UIImage imageNamed:imageName];
if ( image == nil ) break;
[images addObject:[image imageTintedWithColor:tintColor]];
}
return [self animatedImageWithImages:images duration:duration];
}
- (instancetype)imageTintedWithColor:(UIColor *)tintColor
{
CGRect imageBounds = CGRectMake( 0, 0, self.size.width, self.size.height );
UIGraphicsBeginImageContextWithOptions( self.size, NO, self.scale );
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM( context, 0, self.size.height );
CGContextScaleCTM( context, 1.0, -1.0 );
CGContextClipToMask( context, imageBounds, self.CGImage );
[tintColor setFill];
CGContextFillRect( context, imageBounds );
UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return tintedImage;
}
It works just like + [UIImage animatedImageNamed:duration:] (including looking for files named "image0", "image1", etc) except that it also takes a tint color.
Thanks to this answer for providing the image tinting code: https://stackoverflow.com/a/19152722/321527
.tintColor can probably handle it. I use NSTimers for UIButton's setTitleColor method all the time. Here's an example.
UPDATED: Tested and works on iPhone 5s iOS 7.1!
- (void)bringToMain:(UIImage *)imageNam {
timer = [NSTimer scheduledTimerWithTimeInterval:.002
target:self
selector:#selector(animateTint)
userInfo:nil
repeats:YES];
}
- (void)animateTint {
asd += 1.0f;
[imageView setTintColor:[UIColor colorWithRed:((asd/100.0f) green:0.0f blue:0.0f alpha:1.0f]];
if (asd == 100) {
asd = 0.0f
[timer invalidate];
}
}

Resources