I have 7 images which i'm trying to make fade in/out of 1 ImageView. I have stored all the images in an array, and then have a loop to display each image and fade into the next, however, when i run the program only the last 2 images show up. Any ideas on why this is? and how to fix it? Code is below.
imageArray = [NSArray arrayWithObjects:
[UIImage imageNamed:#"image 0.jpg"],
[UIImage imageNamed:#"image 1.jpg"],
[UIImage imageNamed:#"image 2.jpg"],
[UIImage imageNamed:#"image 3.jpg"],
[UIImage imageNamed:#"image 4.jpg"],
[UIImage imageNamed:#"image 5.jpg"],
[UIImage imageNamed:#"image 6.jpg"],
nil];
self.imageview.backgroundColor = [UIColor blackColor];
self.imageview.clipsToBounds = YES;
int count = [imageArray count];
for (int i = 0; i <count-1 ; i++)
{
UIImage *currentImage = [imageArray objectAtIndex: i];
UIImage *nextImage = [imageArray objectAtIndex: i +1];
self.imageview.image = [imageArray objectAtIndex: i];
[self.view addSubview:self.imageview];
CABasicAnimation *crossFade = [CABasicAnimation animationWithKeyPath:#"contents"];
crossFade.duration = 5.0;
crossFade.fromValue = (__bridge id)(currentImage.CGImage);
crossFade.toValue = (__bridge id)(nextImage.CGImage);
[self.imageview.layer addAnimation:crossFade forKey:#"animateContents"];
self.imageview.image = nextImage;
};
Some things to note:
1) You are doing everything synchronously on a loop that has no delay between each transition, there's no point in animating a if on the next loop it will be replaced by the next and so on, until the last 2. Also, you are adding your imageView as a subview every time, also unnecessary.
2) You are changing the .image property of the imageView, and then changing the contents of the layer. Might as well use an UIView and have the same effect.
My recommendation is to make a method to swap from one image to the next, and have a NSTimer call the function every x amount of seconds until you passed through them all.
Edit: For the future:
self.imageview.backgroundColor = [UIColor blackColor];
self.imageview.clipsToBounds = YES;
are completely unnecessary :)
The .backgroundColor is drawn over by the UIImage you are displaying.
The .clipsToBounds is the default behavior of UIImageView (it shrinks/expands your image to it's size, but never draws outside)
Related
I have an array with dictionaries in it. Each dictionary contains UIImage & String values.
But when I try to delete object using
[arr removeObjectAtIndex:button.tag];
then it just decreases the count but image (Object) is not deleted.
So, my Images are overlapping when try to delete.
It also creates problem when I try to add objects in the array
[arr insertObject:dict atIndex:0];
so, I used
[_postObj.arr_images addObject:dict]; instead of insertObject
Help me to solve this
Objects use reference counting and both NSMutableArray and UIImageView will retain the UIImage object.
This means that removing it from the array will not automatically remove it from the UIImageView and you must remove it from both explicitly:
[arr removeObjectAtIndex:button.tag];
_imageView.image = nil;
Problem is in your frame setting of UIImageView. Please try using below code (not tested by myself) and see if this fixes the issue for you. Basically, I am adjusting X position of images based on previous image's width.
CGFloat imageXM = 5.0;
CGFloat imageXPos = 0;
for (UIImage *image in arr_images) {
CGRect imageFrame = CGRectMake(imageXPos + imageXM, 0.0, image.size.width, image.size.height);
imageXPos = imageXPos + image.size.width;
UIImageView *imageView = [[UIImageView alloc] initWithFrame:imageFrame];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.image = image;
[scl addSubview:imageView];
}
As in your code
[picker dismissViewControllerAnimated:YES completion:^{
[arr_images insertObject:chosenImage atIndex:0];
[self scrollImages_Setup2];
}];
[arr_images insertObject:chosenImage atIndex:0]; that means you need only one image to display on scroll view. Then why you take a loop:
-(void)scrollImages_Setup2
{
for (int k=0; k<arr_images.count; k++) {
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake((CGRectGetWidth(scl.frame) * k) + CGRectGetWidth(scl.frame), 0, CGRectGetWidth(scl.frame), CGRectGetHeight(scl.frame))];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.image=[arr_images objectAtIndex:k] ;
[scl addSubview:imageView];
}
scl.contentSize = CGSizeMake((CGRectGetWidth(scl.frame) * arr_images.count)+CGRectGetWidth(scl.frame), CGRectGetHeight(scl.frame));
}
You just right the code only for display the Image. you don't need to scroll view for displaying only one image. I think you are not clear what you want.
Your problem regarding the overwriting the images because of loop. so remove the loop, when you display a single image. Please remove the scrollview contentSize, because image_array will increase, when you add the multiple images in array and size width will be large. so remove arr_images.count as well.
I am interested in obtaining an animation that not only animates from point A to point B but also changes the background image.
Say the initial position is 0,0 and the finis one is 0,100 ; the duration is 1 second, and i have 4 images for the background, then i want the background to change every 0/4 seconds and 25 px.
Until now I have the next code that animates the images but i still need to implement the movement and I don't know how to do just that.
Thanks in advance and here is what code I have until now:
UIImageView * animatedImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 50,50)];
testArray = [[NSArray alloc] initWithObjects:[UIImage imageNamed:#"test_1.png"], [UIImage imageNamed:#"test_2.png"], [UIImage imageNamed:#"test_3.png"],nil];
animTime =3.0;
[animatedImageView setAnimationImages:testArray] ;
animatedImageView.animationDuration = animTime;
animatedImageView.animationRepeatCount = 1;
[self.view addSubview: animatedImageView];
[animatedImageView startAnimating];
UPDATE:
I have implemented the answer of Mobile Project Lab into my code
// I have a pathArray that is in C style and is bidimensional, that stores the path in reverse
// the maps is a 2d tile map
// the dimensions of the tiles are 64x64 px
//thes size of the character is 128x128
for (int possitionInThePathArray = sizeOfPathArray - 1; possitionInThePathArray >= 0; possitionInThePathArray--) {
xWalkingDirection = pathArray[possitionInThePathArray-1][1] - pathArray[possitionInThePathArray][1];
yWalkingDirection = pathArray[possitionInThePathArray-1][0] - pathArray[possitionInThePathArray][0];
if (xWalkingDirection== 0 && yWalkingDirection == -1){
//walking animation to North for 1 tile
NSArray *testArray;
float animTime;
testArray = [[NSArray alloc] initWithObjects:[UIImage imageNamed:#"scientist_s0.png"],
[UIImage imageNamed:#"scientist_s1.png"],
[UIImage imageNamed:#"scientist_s2.png"],
[UIImage imageNamed:#"scientist_s3.png"],
[UIImage imageNamed:#"scientist_s4.png"],
[UIImage imageNamed:#"scientist_s5.png"],
[UIImage imageNamed:#"scientist_s6.png"],
[UIImage imageNamed:#"scientist_s7.png"],
[UIImage imageNamed:#"scientist_s8.png"],
[UIImage imageNamed:#"scientist_s9.png"], nil]; // 4th image added
animTime = 10.0; // time is changed to 10.0
[myCharacterFrame setAnimationImages:testArray];
myCharacterFrame.animationDuration = animTime;
myCharacterFrame.animationRepeatCount = 1;
[myCharacterFrame startAnimating];
[UIView animateWithDuration:animTime
animations:^{
myCharacterFrame.frame = CGRectOffset(myCharacterFrame.frame, 0.0f, -64.0f); // move 100 on x axis, 0 on y axis
}
completion:^(BOOL finished){
NSLog(#"animation done");
}];
yMyCharacterFrame = yMyCharacterFrame-64.0;
myCharacterFrame.frame = CGRectMake(xMyCharacterFrame, yMyCharacterFrame, 128, 128);
myCharacterFrame.image = [UIImage imageNamed:#"scientist_s0.png"];
}else if (xWalkingDirection== 1 && yWalkingDirection == 0){
//walking animation to Est for 1 tile
.....
//and so on for all the four directions of walking
The issue that I am facing now is that the animation are not triggered correctly, so that one animation takes places before the code moves on
NSArray *testArray;
float animTime;
UIImageView *animatedImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
testArray = [[NSArray alloc] initWithObjects:[UIImage imageNamed:#"test_001.png"], [UIImage imageNamed:#"test_002.png"],[UIImage imageNamed:#"test_001.png"], [UIImage imageNamed:#"test_002.png"], nil]; // 4th image added
animTime = 1.0; // time is changed to 1.0
[animatedImageView setAnimationImages:testArray];
animatedImageView.animationDuration = animTime;
animatedImageView.animationRepeatCount = 1;
[self.view addSubview: animatedImageView];
[animatedImageView startAnimating];
[UIView animateWithDuration:animTime
animations:^{
animatedImageView.frame = CGRectOffset(animatedImageView.frame, 100.0f, 0.0f); // move 100 on x axis, 0 on y axis
}
completion:^(BOOL finished){
NSLog(#"animation done");
}];
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];
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];
}
}
I have a set of images facing one side(Man facing right side), and I'm flipping it using this method and then adding it into a uiimageview's animationImages. However after adding in the flipped images, and then start to animate, the animation is still facing the right side.
manRunAnimations = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)];
NSArray *manAniRunArray = #[[UIImage imageNamed:#"robot1"],
[UIImage imageNamed:#"robot2"],
[UIImage imageNamed:#"robot3"],
[UIImage imageNamed:#"robot4"],
[UIImage imageNamed:#"robot5"],
[UIImage imageNamed:#"robot6"],
];
manRunAnimationsf = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)];
NSMutableArray *flippedRunAnimationImages = [[NSMutableArray alloc] init];
for( UIImage *image in manAniRunArray)
{
UIImage * flippedImage = [UIImage imageWithCGImage:image.CGImage scale:image.scale orientation:UIImageOrientationRightMirrored];
[flippedRunAnimationImages addObject:flippedImage];
}
manRunAnimationsf.animationImages = (NSArray *)flippedRunAnimationImages;
testImgView.image = [manRunAnimationsf.animationImages objectAtIndex:0];
manRunAnimationsf.animationDuration = runAnimationSpeedSlider.value;
[manRunAnimationsf startAnimating];
I've even tested it using
testImgView.image = [manRunAnimationsf.animationImages objectAtIndex:5];
This would display one of the flipped images properly on screen just before I do a
[manRunAnimationsf startAnimating];
Once it starts, the animations are not flipped at all!!
Anyone know why?
I can't believe no one knows why, but I found way around it. Is to add the following before I startAnimating:
manRunAnimationsf.transform = CGAffineTransformMake(-1,0,0,1,0,0);
I didn't even need to do the CGImage flips in that for loop.
But the manual image flip should have worked with the imageWithCGImage method, and I really want to know why!! You guys disappoint me. :p