I've searched everywhere but I did not find a proper solution for my problem. I have a image-sequence playing on start up. After this sequence I want to trigger a function. A function that activates an Image which. So the animation will run fluently into the image without break. I found a lot of solutions on the internet e.g. doing it with a timer but running the code via simulator it works, on device it doesn't and gets delayed :(. Is it a good way to set the timer just by testing when the animation is finished? The method "animationDone" is always triggered on the wrong time!
Here my example code:
- (void)viewDidLoad {
imageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"Rad_start_00000.png"],
[UIImage imageNamed:#"Rad_start_00001.png"],
[UIImage imageNamed:#"Rad_start_00002.png"],
[UIImage imageNamed:#"Rad_start_00003.png"],
[UIImage imageNamed:#"Rad_start_00004.png"],
[UIImage imageNamed:#"Rad_start_00005.png"],
[UIImage imageNamed:#"Rad_start_00006.png"],
[UIImage imageNamed:#"Rad_start_00007.png"],
[UIImage imageNamed:#"Rad_start_00008.png"],
[UIImage imageNamed:#"Rad_start_00009.png"],
[UIImage imageNamed:#"Rad_start_00010.png"],
[UIImage imageNamed:#"Rad_start_00011.png"],
[UIImage imageNamed:#"Rad_start_00012.png"],
[UIImage imageNamed:#"Rad_start_00013.png"],
[UIImage imageNamed:#"Rad_start_00014.png"],
[UIImage imageNamed:#"Rad_start_00015.png"],
[UIImage imageNamed:#"Rad_start_00016.png"],
[UIImage imageNamed:#"Rad_start_00017.png"],nil];
[imageView setAnimationDuration:0.7];
[imageView setAnimationRepeatCount:1];
[imageView startAnimating];
[self performSelector:#selector(animationDone) withObject:nil afterDelay:1.2];
}
First, you should try using the same interval for both the afterDelay parameter to performSelector and the setAnimationDuration (e.g., 0.7 seconds for both).
If that doesn't quite do what you want, you can programmatically call timer, constantly checking to see if the animation is done. For example, you could set up a display link (it's like a timer, but linked to updates to the display), and check imageView.isAnimating, e.g.:
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
#property (nonatomic, strong) CADisplayLink *displayLink;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.imageView.animationImages = #[[UIImage imageNamed:#"Rad_start_00000.png"],
[UIImage imageNamed:#"Rad_start_00001.png"],
[UIImage imageNamed:#"Rad_start_00002.png"],
[UIImage imageNamed:#"Rad_start_00003.png"],
[UIImage imageNamed:#"Rad_start_00004.png"],
[UIImage imageNamed:#"Rad_start_00005.png"],
[UIImage imageNamed:#"Rad_start_00006.png"],
[UIImage imageNamed:#"Rad_start_00007.png"],
[UIImage imageNamed:#"Rad_start_00008.png"],
[UIImage imageNamed:#"Rad_start_00009.png"],
[UIImage imageNamed:#"Rad_start_00010.png"],
[UIImage imageNamed:#"Rad_start_00011.png"],
[UIImage imageNamed:#"Rad_start_00012.png"],
[UIImage imageNamed:#"Rad_start_00013.png"],
[UIImage imageNamed:#"Rad_start_00014.png"],
[UIImage imageNamed:#"Rad_start_00015.png"],
[UIImage imageNamed:#"Rad_start_00016.png"],
[UIImage imageNamed:#"Rad_start_00017.png"]];
[self.imageView setAnimationDuration:0.7];
[self.imageView setAnimationRepeatCount:1];
[self.imageView startAnimating];
[self startDisplayLink];
}
- (void)startDisplayLink
{
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(handleDisplayLink:)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
}
- (void)stopDisplayLink
{
[self.displayLink invalidate];
self.displayLink = nil;
}
- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
if (!self.imageView.isAnimating) {
[self stopDisplayLink];
NSLog(#"done");
// do whatever else you want here
}
}
#end
try using the delegate of the animation
and the setAnimationDidStopSelector:
https://developer.apple.com/library/ios/documentation/uikit/reference/UIView_Class/UIView/UIView.html#//apple_ref/occ/clm/UIView/setAnimationDelegate:
Related
After build code, it doesn't have any animation on my cellphone
but the code looks good, i don't know how to figure it out ,
and my image is 829 * 445, does it cause this problem ?
Could someone help me to solve this problem i will really appreciate it, thanks
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSArray *animationImages = [NSArray arrayWithObjects:[UIImage imageNamed:#"1.jpg"],
[UIImage imageNamed:#"2.jpg"],
[UIImage imageNamed:#"3.jpg"],
[UIImage imageNamed:#"4.jpg"],nil];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,150,150)];
imageView.animationImages = animationImages ;
imageView.animationRepeatCount = 2;
imageView.animationDuration= 4.0;
[imageView startAnimating];
[NSTimer scheduledTimerWithTimeInterval:4.0 target:self
selector:#selector(animationDone:)
userInfo:nil repeats:NO];
}
-(void)animationDone:(NSTimer*)inTimer
{
[inTimer invalidate];
inTimer = nil;
NSLog(#"animationDone ");
}
#end
You don't added imageView to your ViewController view.
Try [self.view addSubview:imageView]; in -viewDidLoad
Please use animation block code instead of the older method. The animation will tell you when its done. You don't need to set a timer.
NSArray *animationImages = [NSArray arrayWithObjects:[UIImage imageNamed:#"1.jpg"],
[UIImage imageNamed:#"2.jpg"],
[UIImage imageNamed:#"3.jpg"],
[UIImage imageNamed:#"4.jpg"],nil];
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,150,150)];
[UIView animateWithDuration:1.0f animations:^{
for (int loop = 0; loop < 4; loop++) {
UIImage *image = [UIImage imageNamed:[NSString stringWithFornmat:#"%d.jpg", (loop + 1)]];
[imageView setImage:image];
}
} completion:^(BOOL finished) {
NSLog(#"animationDone");
}];
It looks like you're not adding the animating UIImageView to your view hierarchy. Right before your [imageView startAnimating]; line add the below line of code:
[self.view addSubview:imageView];
I am trying to set up a button that plays an animation in an image view that's part of my root view controller and then proceed to change the sub view controller.
But for some reason, the code changes the view controller and THEN plays the animation.
I would think that the animation segment would be implemented before the view controller change takes place because, well, it's first in the code.
The code does everything fine, it just does it backwards. Any one have any ideas of what's going wrong?
- (IBAction)next:(UIButton *)sender {
clouds.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"cloudAnim.0001.png"],
[UIImage imageNamed:#"cloudAnim.0002.png"],
[UIImage imageNamed:#"cloudAnim.0003.png"],
[UIImage imageNamed:#"cloudAnim.0004.png"],
[UIImage imageNamed:#"cloudAnim.0005.png"],
[UIImage imageNamed:#"cloudAnim.0006.png"],
[UIImage imageNamed:#"cloudAnim.0007.png"],
[UIImage imageNamed:#"cloudAnim.0008.png"],
[UIImage imageNamed:#"cloudAnim.0009.png"],
[UIImage imageNamed:#"cloudAnim.0010.png"],
[UIImage imageNamed:#"cloudAnim.0011.png"],
[UIImage imageNamed:#"cloudAnim.0012.png"],
[UIImage imageNamed:#"cloudAnim.0013.png"],
[UIImage imageNamed:#"cloudAnim.0014.png"],
[UIImage imageNamed:#"cloudAnim.0015.png"],
[UIImage imageNamed:#"cloudAnim.0016.png"],
[UIImage imageNamed:#"cloudAnim.0017.png"],
[UIImage imageNamed:#"cloudAnim.0018.png"],
[UIImage imageNamed:#"cloudAnim.0019.png"],
[UIImage imageNamed:#"cloudAnim.0020.png"],
[UIImage imageNamed:#"cloudAnim.0021.png"],
[UIImage imageNamed:#"cloudAnim.0022.png"],
[UIImage imageNamed:#"cloudAnim.0023.png"],
[UIImage imageNamed:#"cloudAnim.0024.png"],
[UIImage imageNamed:#"cloudAnim.0025.png"],
[UIImage imageNamed:#"cloudAnim.0026.png"],
[UIImage imageNamed:#"cloudAnim.0027.png"],
[UIImage imageNamed:#"cloudAnim.0028.png"],
[UIImage imageNamed:#"cloudAnim.0029.png"],
[UIImage imageNamed:#"cloudAnim.0030.png"],
[UIImage imageNamed:#"cloudAnim.0031.png"],
[UIImage imageNamed:#"cloudAnim.0032.png"],
[UIImage imageNamed:#"cloudAnim.0033.png"],
[UIImage imageNamed:#"cloudAnim.0034.png"],
[UIImage imageNamed:#"cloudAnim.0035.png"],
[UIImage imageNamed:#"cloudAnim.0036.png"],
[UIImage imageNamed:#"cloudAnim.0037.png"],
[UIImage imageNamed:#"cloudAnim.0038.png"],
[UIImage imageNamed:#"cloudAnim.0039.png"],
[UIImage imageNamed:#"cloudAnim.0040.png"],
[UIImage imageNamed:#"cloudAnim.0041.png"],
[UIImage imageNamed:#"cloudAnim.0042.png"],
[UIImage imageNamed:#"cloudAnim.0043.png"],
[UIImage imageNamed:#"cloudAnim.0044.png"],
[UIImage imageNamed:#"cloudAnim.0045.png"],
[UIImage imageNamed:#"cloudAnim.0046.png"],
[UIImage imageNamed:#"cloudAnim.0047.png"],
[UIImage imageNamed:#"cloudAnim.0048.png"], nil];
[clouds setAnimationRepeatCount:1];
clouds.animationDuration = 2.0;
[clouds startAnimating];
if (currentPage == 1){
self.page02ViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"page02"];
[self.view insertSubview:_page02ViewController.view atIndex:0];
[self.page01ViewController.view removeFromSuperview];
}
if (currentPage == 2){
self.page03ViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"page03"];
[self.page02ViewController.view removeFromSuperview];
[self.view insertSubview:_page03ViewController.view atIndex:0];
}
currentPage = currentPage +1;
if (currentPage >3){
currentPage = 3;
}
}
Animations are asynchronous, meaning the code below will be executed immediately.
If you want to wait until one loop of the animation has completed, you'll need to delay the code afterward. The simplest way is to use dispatch_after:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// Your view controller switching code will be executed after 2 seconds...
});
Beware that, since the method returns immediately, there is nothing stopping the user from hitting the button again and queuing up another transition. You may wish to disable user interaction during the transition, though a 2-second transition will feel like an eternity to the user if they have to switch often.
I have two different images, that are essentially just inverses of each other. I would like to animate them back and forth to create a somewhat moving effect. In the AppDelegate didFinishLaunching I have:
myImageWalk = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, 320, 568)];
[self.myImageWalk setImage: [self loadingImage]];
[window addSubview:myImageWalk];
[window bringSubviewToFront:myImageWalk];
Then, also in the App Delegate, I have:
-(UIImage*)loadingImage
{
NSArray *animationFrames = [NSArray arrayWithObjects:
[UIImage imageNamed:#"original.png"],
[UIImage imageNamed:#"second.png"],
[UIImage imageNamed:#"original.png"],
[UIImage imageNamed:#"second.png"],
[UIImage imageNamed:#"original.png"],
[UIImage imageNamed:#"second.png"],
[UIImage imageNamed:#"original.png"],
[UIImage imageNamed:#"second.png"],
[UIImage imageNamed:#"original.png"],
[UIImage imageNamed:#"second.png"],
[UIImage imageNamed:#"original.png"],
[UIImage imageNamed:#"second.png"],
[UIImage imageNamed:#"original.png"],
[UIImage imageNamed:#"second.png"],
[UIImage imageNamed:#"original.png"],
[UIImage imageNamed:#"second.png"],
[UIImage imageNamed:#"original.png"],
[UIImage imageNamed:#"second.png"],
nil];
return [UIImage animatedImageWithImages:animationFrames duration:6.0f];
}
But, nothing happens, no image ever shows up. What am I doing wrong?
Some code below you can try.
Note you don't need to repeat the series of imageNamed:, just set duration as needed for one loop.
myImageWalk = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, 320, 568)];
myImageWalk.image = [self loadingImage];
self.myImageWalk.animationRepeatCount = 0;
[window addSubview:myImageWalk];
[window bringSubviewToFront:myImageWalk];
//when you want the animation to start
[self animateImages];
//then later at some appropriate time:
[self stopAnimatingImages];
- (UIImage*)loadingImage {
NSArray *animationFrames = [NSArray arrayWithObjects:
[UIImage imageNamed:#"original.png"],
[UIImage imageNamed:#"second.png"],
nil];
return [UIImage animatedImageWithImages:animationFrames duration:6.0f];
}
- (void)animateImages {
if (![self.myImageWalk isAnimating]) {
[self.myImageWalk startAnimating];
}
}
- (void)stopAnimatingImages {
if ([self.myImageWalk isAnimating]) {
[self.myImageWalk stopAnimating];
}
}
Note: unless this is a test app or class assignment, you should move this logic from AppDelegate to ViewContoller, as it is best practice to minimize the work done during didFinishLaunching.
I haven't tried it, but maybe try wrapping your code inside this block:
[UIView animateWithDuration:6f animations:^{
[UIImage animatedImageWithImages:animationFrames duration:6.0f]
} completion:^(BOOL finished) {
//Callback after animation was completed
[view removeFromSuperview];
}];
I have successfully created a UIView which plays an animation of images from an NSArray of images. I am trying to get this image to move at the same time the animation is playing. Use of the .center property of UIView just isn't working, and I must have some sort of syntactic error, which I cannot for the life of me figure out.
Original post:
I'm playing with brandontreb's tutorial. I can successfully get the animated sprite to dance in place, but I want it to actually scoot across the screen. Can some dear soul:
Please help me fix what I'm doing wrong to make the center of the UIimage
actually move across screen?
Or even better, update this to
"animation block" best practices?
I will surely study your fixes for hours.
- (IBAction)startWalking:(UIButton *)sender {
NSArray * imageArray = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:#"1.png"],
[UIImage imageNamed:#"2.png"],
[UIImage imageNamed:#"3.png"],
[UIImage imageNamed:#"4.png"],
[UIImage imageNamed:#"5.png"],
[UIImage imageNamed:#"6.png"],
[UIImage imageNamed:#"7.png"],
[UIImage imageNamed:#"8.png"],
[UIImage imageNamed:#"9.png"],
[UIImage imageNamed:#"10.png"],
[UIImage imageNamed:#"11.png"],
[UIImage imageNamed:#"12.png"],
nil];
UIImageView * ryuJump = [[UIImageView alloc] initWithFrame:
CGRectMake(100, 125, 150, 130)];
ryuJump.animationImages = imageArray;
ryuJump.animationDuration = 1.1;
ryuJump.animationRepeatCount=5;
CGPoint p = ryuJump.center;
p.x += 100;
ryuJump.center = p;
[UIView animateWithDuration:20
delay:0
options: UIViewAnimationOptionCurveEaseIn
animations:^{
ryuJump.center = CGPointMake(p.x, p.y);
}
completion:^(BOOL finished){
}];
ryuJump.contentMode = UIViewContentModeBottomLeft;
[self.view addSubview:ryuJump];
[ryuJump startAnimating];
}
Remove:
ryuJump.center = p;
You're basically telling uiview to animate to the exact same position you just set it to (so nothing will happen).
I am doing an UIImageView animation like so:
//////progressbar start
progressbar.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"1.png"],
[UIImage imageNamed:#"2.png"],
[UIImage imageNamed:#"3.png"],
[UIImage imageNamed:#"4.png"],
[UIImage imageNamed:#"5.png"],
[UIImage imageNamed:#"6.png"],
[UIImage imageNamed:#"7.png"],
[UIImage imageNamed:#"8.png"],
[UIImage imageNamed:#"9.png"],
[UIImage imageNamed:#"10.png"],
[UIImage imageNamed:#"11.png"],
[UIImage imageNamed:#"12.png"],
[UIImage imageNamed:#"13.png"],
[UIImage imageNamed:#"14.png"],
[UIImage imageNamed:#"15.png"],
[UIImage imageNamed:#"16.png"],
[UIImage imageNamed:#"17.png"],
[UIImage imageNamed:#"18.png"],
[UIImage imageNamed:#"19.png"],
[UIImage imageNamed:#"20.png"],
[UIImage imageNamed:#"21.png"],
[UIImage imageNamed:#"22.png"],
[UIImage imageNamed:#"23.png"],
[UIImage imageNamed:#"24.png"],
[UIImage imageNamed:#"25.png"],
[UIImage imageNamed:#"26.png"],
[UIImage imageNamed:#"27.png"],
[UIImage imageNamed:#"28.png"],
[UIImage imageNamed:#"29.png"],
[UIImage imageNamed:#"30.png"],
[UIImage imageNamed:#"31.png"],
[UIImage imageNamed:#"32.png"],
[UIImage imageNamed:#"33.png"],
[UIImage imageNamed:#"34.png"],
[UIImage imageNamed:#"35.png"],
[UIImage imageNamed:#"36.png"],
[UIImage imageNamed:#"37.png"],
[UIImage imageNamed:#"38.png"],
[UIImage imageNamed:#"39.png"],
[UIImage imageNamed:#"40.png"],
[UIImage imageNamed:#"41.png"],
[UIImage imageNamed:#"42.png"], nil];
progressbar.animationDuration = 5.00;
progressbar.animationRepeatCount = 0;
[progressbar startAnimating];
Now I need to pause it so once the user clicks the button the images will not animate and will stay on the current image.
I got this code off the web to pause it,
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.
Will that code work? Also how would I then unpause it from the current image?
I also tried to use this code and it didn't work.
Instead you can use the code provided by apple in the following link to pause and resume your animation.
http://developer.apple.com/library/ios/#qa/qa1673/_index.html
To get the CALayer to pass to the pauseLayer function, you can use the following code.
CALayer *player = progressbar.layer;
[self pauseLayer:player];
Here is my approach:
- (IBAction)play:(id)sender
{
pauseAnimation = FALSE;
[self performSelector:#selector(changeImages) withObject:nil afterDelay:0];
[self.pauseButton setHidden:NO];
[self.playButton setHidden:YES];
}
- (IBAction)pause:(id)sender
{
pauseAnimation = TRUE;
[self.pauseButton setHidden:YES];
[self.playButton setHidden:NO];
}
- (void)changeImages
{
if (currentFrame == self.selectedAttachment.noOfFrames)
{
currentFrame = -1;
return; //Don't use return, if a looped playing is required.
}
if (currentFrame == -1) {
currentFrame = 0;
}
if (pauseAnimation)
{
return;
}
[self performSelector:#selector(changeImages) withObject:nil afterDelay:.5];
imageView.image = [frameArray objectAtIndex:currentFrame];
currentFrame ++;
}
Even you can change the images in between...
- (IBAction)replaceImage:(id)sender
{
UIImage *replaceImage = [[UIImage alloc]init];
replaceImage = [UIImage imageNamed:#"Bluehound.gif"];
int i = arc4random()%25;
[frameArray replaceObjectAtIndex:i withObject:replaceImage];
}
Thanks all. You can now play,pause,replace images etc.
*there is a bug : tapping on play button again increases the speed...:P
Please try stopAnimating
[progressBar stopAnimating];