IPhone provides smooth animation using a runtime timer

I'm trying to implement a simple quiz app on iphone in the spirit of learning, a timer is part of this app.

I want my timer to count from 10 to 0. I had a simple NSTimer that repeats and calls the method every second, and in this method I update the shortcut that displays the remaining time, which works great.

Now instead of displaying a timer using a label, I wanted to use a graphical progress bar, so I created ten images, one full in length (representing 10), the next 9/10 in size and so on, and in my re-timer method instead of updating I update the UIImage tags with the corresponding image, so over time the progress bar gets smaller and smaller.

My problem is that thanks to the way I implemented the progress bar, it doesn't look very smooth when it is updated every second. Is there any other way that I should approach developing such kind of functions? I heard that you can use a stretch image to get a smoother effect, but I could not see good examples of this.

Any tips and code examples are welcome just trying to find out here.

+4
source share
3 answers

After exploring several options, I decided to use UIProgressView (suggested by sudo in the comments) in combination with NSTimer, which updates progress ten times per second for ten seconds, I used this solution because:

  • This is a standard item provided by apple.
  • This option has no overhead for creating and uploading 100 images (as suggested by Krypton in the comments).
  • In NSTimer, I can add a check to the updateProgressBar function to add some feedback to the user when the timer reaches a low level, i.e. vibration for the last three seconds, etc. (using animation, I don’t think I will have such an option).

Using the code below, suppose I have a UIProgressView variable named "progressView", an NSTimer named "timer" and a floating point variable named "time", and then:

-(void)updateProgressBar { if(time <= 0.0f) { //Invalidate timer when time reaches 0 [timer invalidate]; } else { time -= 0.01; progressView.progress = time; } } -(void)animateProgressView2 { progressView.progress = 1; time = 1; timer = [NSTimer scheduledTimerWithTimeInterval: 0.1f target: self selector: @selector(updateProgressBar) userInfo: nil repeats: YES]; } 

Another way that I explored (seeing Disco comments), but decided not to use animation. In this case, I created two png-images called "redbar.png" and "greenbar.png", the idea forced them to be placed on top of each other (the green bar on the top / in the foreground) and for the duration of the animation the green bar is compressed, showing the red strip in the background.

 UIImage *green= [UIImage imageNamed:@"greenbar.png"]; UIImage *red= [UIImage imageNamed:@"redbar.png"]; redBar.image = red; // allocate the red image to the UIImageView redBar.frame = CGRectMake(20,250,220,30);// set the size of the red image greenBar.image = green; // allocate the green image to the UIImageView greenBar.frame = CGRectMake(20,250,220,30);//set the size of the green image [UIView beginAnimations:nil context:nil]; [UIView setAnimationDelegate:self]; [UIView setAnimationDuration:10]; //the time you want the animation to last for [UIView setAnimationDidStopSelector:@selector(animationFinished)];//the method to be called once the animation is finished //at the end of the animation we want the greenBar frame to disappear greenBar.frame = CGRectMake(20,250,0,30); [UIView commitAnimations]; 

An ideal solution would be to combine the UIProgressView and the UIAnimation block, but this is currently not an option (see this question to animate a change in the UIProgressView ).

Hope this helps someone in the future.

EDIT ::

It seems that the ideal solution that I mentioned above is now available in iOS5, taken from Apple's reference site:

setProgress: animated: Adjusts the current progress shown by the receiver, animating the change as necessary.

  • (void) setProgress: (float) progress animated: (BOOL) animated
+5
source

It may not be what you are looking for, but it can help you. Why not have a UIImageView with your image in full size and then apply multiple UIView animations to it over a given time? Thus, the compression will be smooth.

 UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"YourImage.png"]]; imageView.frame = CGRectMake(0,0,320,30);//starts big [self.view addSubview:imageView]; [UIView beginAnimations:@"Progress Bar Animation" Context:nil]; [UIView setAnimationDuration:10]; //whatever time you want imageView.frame = CGRectMake(0,0,10,30);//ends small [UIView commitAnimations]; 

This may be what you are looking for, I'm not sure. It just seems a little easier than using ten different images.

+1
source

I did it by increasing the tuning progress from (0.01-1.00) to (0.001-1000) and reducing the time difference between setting the progress values.

Here is my code below with three different animation speeds.

  -(void)setProgressViewProgress { //Check for completion if(progress > 1.0) { [self progressCompleted]; return; } //Diffrent speed for range CGFloat speed; //From 0.000 to 0.500 speed is 500*0.007 = 3.5 seconds 0.007(sec) => x(sec) = Total time in range(sec) / 500.0 ==> 3.5/500.0 = 0.07 if(progress<0.50) { speed = 0.007; } //From 0.500 to 0.750 speed is 250*0.005 = 1.25 seconds 0.005(sec) => x(sec) = Total time in range(sec) / 500.0 ==> 1.25/250.0 = 0.05 else if(progress<0.75) { speed = 0.005; } //From 0.750 to 1.0 speed is 250*0.002 = 0.5 seconds 0.002(sec) => x(sec) = Total time in range(sec) / 500.0 ==> 0.5/250.0 = 0.02 else { speed = 0.002; } //Increase the progress view by 1/1000 for smooth animation progress+=0.001; [progressView setProgress:progress]; [self performSelector:@selector(setProgressViewProgress) withObject:nil afterDelay:speed]; } 
0
source

All Articles