count up from 0.00 to 176.20 with NSTimer - ios

I am working on an app and I want to animate the numbers in my app. I know I need to use an NSTimer. Just not sure how. For example I want the app to count up from 0.00 to 176.20 (self.total.text).
NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(update) userInfo:nil repeats:YES];
- (void)update{
float currentTime = [self.total.text floatValue];
float newTime = currentTime + 0.1;
self.total.text = [NSString stringWithFormat:#"%f", newTime];
}

You need to decide at what increment you want to count. You want to stop at 176.20 so it seems like an increment of 0.1 seconds would be what you want. You need a variable to store the current position.
Obj-c///
const float limit = 176.2f
#property (nonatomic) float seconds;
#property (nonatomic, strong) NSTimer *updateTimer;
// Initialize
self.seconds = 0.0f;
self.updateTimer = [NStimer scheduledTimerWithTimeInterval:0.1f target:self selector:#selector(timerFired) userInfo:nil repeats:true];
Swift///
var seconds = 0.0
let limit = 176.2
let timer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("timerFired"), userInfo: nil, repeats: true)
Then you need to create a function which is used to update the label every time the timer fires and a function which schedules the timer.
Obj-c///
- (void)timerFired {
self.seconds += 0.1f;
self.label.text = [NSString stringWithFormat:#"%f", self.seconds];
if (self.seconds >= limit) {
[self.updateTimer invalidate];
}
}
Swift///
func timerFired() {
seconds += 0.1 //Increment the seconds
label.text = "\(seconds)" //Set the label
if (seconds >= limit) {
timer.invalidate()
}
}

Related

Animation using NSTimer and the position of the UIImageView frame

Hi and thanks in advance for any help and contribution :)
I am currently working on a personal project(some sort of a mmorpg) AND I'am stuck at the walking animation.
Until now I have made the map and implemented the A* pathfinder that returns a path array in C style.
What I am trying to do is to change the background image of an UIImageFrame and de/increment its x and y position depending on the values stored in an array.
The ideea was to change the background image and de/increase X or Y by 2px using an NSTimer, every 0,1s.
The NStimer will call the animation function 32 times before it is invalidated.
And here is the code for the 4 possible directions( N/S/W/E):
In the .h file:
#import <UIKit/UIKit.h>
int xMyCharacterFrame;
int yMyCharacterFrame;
#interface ViewController : UIViewController
{
int counterInMilisecondsForAnimation;
UIImageView *myCharacterFrame ;
}
#property (strong, nonatomic) NSTimer *timerForSouthMoving;
#property (strong, nonatomic) NSTimer *timerForNorthMoving;
#property (strong, nonatomic) NSTimer *timerForEstMoving;
#property (strong, nonatomic) NSTimer *timerForWestMoving;
-(void)southAnimation;
-(void)northAnimation;
-(void)estAnimation;
-(void)westAnimation;
#end
In the .m file:
- (void)viewDidLoad {
[super viewDidLoad];
myCharacterFrame = [[UIImageView alloc]init];
myCharacterFrame.frame = CGRectMake(xMyCharacterFrame, yMyCharacterFrame, 100, 100);
myCharacterFrame.image = [UIImage imageNamed:#"scientist_s0.png"];
}
When the game is started the xMyCharacterFrame are laoded form NSUserDefaults. ANd the recalculated depending on the user tap. The game is a 2d map based, with tiles of 64*64 px.
-(void)findPathForStart:(int)start andFinish:(int)stop{
//after the path is find using the self implemented A* pathfinder, the walking animation should use
the resulted path find array, that is two dimensional, first position Y and on the second the X.
On the fist 2d array of the path array I store the finish position, so in order to animate I need to read it in reverse.
int xWayOfMoving;
int yWayOfMoving;
for (int possitionInThePathArray = sizeOfPathArray - 1; possitionInThePathArray >= 0; possitionInThePathArray--) {
xWayOfMoving= pathArray[possitionInThePathArray-1][1] - pathArray[possitionInThePathArray][1];
yWayOfMoving= pathArray[possitionInThePathArray-1][0] - pathArray[possitionInThePathArray][0];
if (xWayOfMoving== 0 && yWayOfMoving== 1) {
//animate north
[timerForSouthMoving invalidate];
timerForSouthMoving = nil;
counterInMilisecondsForAnimation= 0;
timerPentruAnimatieDeplasare = [NSTimer scheduledTimerWithTimeInterval: 0.1
target: self
selector:#selector(northAnimation)
userInfo: nil
repeats:YES];
}else if (xWayOfMoving== 0 && yWayOfMoving== -1){
//animate south
[timerForNorthMoving invalidate];
timerForNorthMoving= nil;
counterInMilisecondsForAnimation= 0;
timerForNorthMoving= [NSTimer scheduledTimerWithTimeInterval: 0.1
target: self
selector:#selector(northAnimation)
userInfo: nil
repeats:YES];
}else if (xWayOfMoving== 1 && yWayOfMoving== 0){
// animate west
[timerForWestMovinginvalidate];
timerForWestMoving= nil;
counterInMilisecondsForAnimation= 0;
timerForWestMoving = [NSTimer scheduledTimerWithTimeInterval: 0.1
target: self
selector:#selector(northAnimation)
userInfo: nil
repeats:YES];
}else if (xWayOfMoving== -1 && yWayOfMoving == 0){
//animate est
[timerForEstMoving invalidate];
timerForEstMoving = nil;
counterInMilisecondsForAnimation= 0;
timerForEstMoving = [NSTimer scheduledTimerWithTimeInterval: 0.1
target: self
selector:#selector(northAnimation)
userInfo: nil
repeats:YES];
}
}
}
One of the 4 functions for the walking animation:
-(void)northAnimation{
if (counterInMilisecondsForAnimation< 33) {
if (counterCharacterImageSouth == 11) {
counterCharacterImageSouth = 0;}
myCharacterFrame.frame = CGRectMake(xMyCharacterFrame, yMyCharacterFrame, 100, 100);
myCharacterFrame.image = [UIImage imageNamed:[NSString stringWithFormat:#"scientist_s%d.png", counterCharacterImageSouth]];
yMyCharacterFrame = yMyCharacterFrame - 2;
counterCharacterImageSouth++;
counterInMilisecondsForAnimation++;
}
else{
[timerForSouthMoving invalidate];
}
}

working with UIProgressView to set progress bar to 30 minutes

I'm working on an project were I have put in a progress bar and then set a button to start the progressbar when it is pressed. The thing is that I want to have the progress in 30min when you pressed the startbutton, so I need help to set it to 30 minutes.
Here is my code to setup the progressbar and startbutton
the m-file
- (IBAction)StartButton:(id)sender {
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(moreProgress)
userInfo:Nil repeats:YES];
[super viewDidLoad];
//progressbar start when button pressed
}
and then i got this for the time
//selector progress time
- (void) moreProgress {
myProgressView.progress += 0.001;
}
I think it's only a math problem.
First, myProgressView.progress can assume values from 0.0 to 1.0.
As you call moreProgress each second, you'll need to call it 1800 times for 30 minutes. Thus, myProgressView.progress should increase 1/1800 by second.
Change your code to:
- (void) moreProgress {
myProgressView.progress += 1.0/1800.0;
}
Hope it helps you! :)
1)Save the Current Time (You can save it to NSUserDefaults by example).
You can do something like That:
NSUserDefaults *user1 = [NSUserDefaults standardUserDefaults];
NSDate *currentDate = [NSDate date];
[user1 setObject:[NSNumber numberWithDouble:[currentDate timeIntervalSince1970]] forKey:#"time"];
[user1 synchronize];
2)schedule the call to your function like you did it
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(moreProgress)
userInfo:Nil repeats:YES];
3)Next in your function you need to update the progress view status with something like that:
//selector progress time
- (void) moreProgress {
NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
NSDate *startTime = [NSDate dateWithTimeIntervalSince1970:[[user objectForKey:#"time"]doubleValue]];
NSTimeInterval elapsedTime = [startTime timeIntervalSinceNow];
float progress = (float)elapsed time / 30.0 * 60.0;
myProgressView.progress = progress;
if ((float)elapsedTime / 30 * 60 >= 1)
{
// The timer is end, you should stop it and do what you need
}
}
Note:
It s not safe to expect that
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(moreProgress)
will fire up each seconds. It s not guaranteed and not precise.
// This extension will help you. I'had used this extension and it really work for me.
extension UIProgressView {
#available(iOS 10.0, *)
func setAnimatedProgress(progress: Float = 1, duration: Float = 1, completion: (() -> ())? = nil) {
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { (timer) in
DispatchQueue.main.async {
let current = self.progress
self.setProgress(current+(1/duration), animated: true)
}
if self.progress >= progress {
timer.invalidate()
if completion != nil {
completion!()
}
}
}
}
}
// Just call this extension with your UIProgressView like this
YOUR_PROGRESS_VIEW.setAnimatedProgress(duration: 100) { // Here 100 meaning 10 seconds
debugPrint("Done!")
}

Random Positioning issue

I am trying atm doing a game. I got some problems with the RandomPositioning with the blocks. With my code, the Blocks keep spawning at the same lane very fast. But thats not what I mean to. They should appear like a Mario Game. My Code:
HumanMovement = [NSTimer scheduledTimerWithTimeInterval:0.03 target:self selector:#selector(HumanMoving) userInfo:nil repeats:YES];
[self PlaceBlocks];
BlockMovement = [NSTimer scheduledTimerWithTimeInterval:0.03 target:self selector:#selector(BlockMoving) userInfo:nil repeats:YES];
}
-(void)BlockMoving{
StartingBlock.center = CGPointMake(StartingBlock.center.x -1, StartingBlock.center.y);
Block1.center = CGPointMake(Block1.center.x -1, Block1.center.y);
Block2.center = CGPointMake(Block2.center.x -1, Block2.center.y);
if ( Block1.center.x > 20) {
[self PlaceBlocks];
}
}
-(void)PlaceBlocks{
RandomBlock1Position = arc4random() %568;
RandomBlock1Position = RandomBlock1Position + 140;
RandomBlock2Position = RandomBlock2Position + 500;
Block1.center = CGPointMake(193 , RandomBlock1Position);
Block2.center = CGPointMake(280 , RandomBlock2Position);
}
So if i understood correctly your blocks should respawn once the reach the left side. In order to do so you have to change your center check position to :
if ( Block1.center.x < 20) {
[self PlaceBlocks];
}

Displaying a u int. I get a positive number when i subtract 1 when the value is 0

I got a unsigned integer for a timer. But when I subtract 1 of it when the value is zero it displays a positive number. Like this: http://prntscr.com/2wkydb .
Here's my code Viewcontroller.m:
-(IBAction)btnUp:(id)sender
{
timer = timer + 1;
lblTimer.text = [NSString stringWithFormat:#"%u", timer];
}
-(IBAction)btnDown:(id)sender
{
timer = timer - 1;
lblTimer.text = [NSString stringWithFormat:#"%u", timer];
}
-(IBAction)btnRestart:(id)sender
{
lblTimer.text = [NSString stringWithFormat:#"0"];
}
Viewcontroller.h:
#interface ViewController : UIViewController
{
unsigned int timer;
IBOutlet UILabel *lblTimer;
}
-(IBAction)btnUp:(id)sender;
-(IBAction)btnDown:(id)sender;
-(IBAction)btnRestart:(id)sender;
#end
What do I need to do so it doesn't display the positive number but the timer stays on 0?
Thanks in advance.
Edit: I also don't want the timer to display a negative value.
Unsigned integers "wrap around". Subtracting 1 from zero gives (assuming 32-bit integers):
0xFFFFFFFF = 4294967295
If you don't want that then change your code to:
if (timer > 0)
timer = timer - 1;
Even better, disable the "Down" button when the value reaches zero, and enable
it again when the value is positive.
Something like (untested, not compiler checked):
-(IBAction)btnUp:(UIButton *)sender
{
timer = timer + 1;
lblTimer.text = [NSString stringWithFormat:#"%u", timer];
self.downButton.enabled = YES;
}
-(IBAction)btnDown:(UIButton *)sender
{
timer = timer - 1;
lblTimer.text = [NSString stringWithFormat:#"%u", timer];
sender.enabled = (timer > 0);
}

How to rotate an UIView around it's center, with 1 minute duration, 1 second intervals and a silky smooth animation?

I'm trying to rotate an UIView. This UIView represents the seconds pointer of a clock.
I need to update it every second. Like this:
- (void)startUpdates {
_updateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(animatePointer) userInfo:nil repeats:YES];
}
Stop it when I need it to, like this:
- (void)stopUpdates {
[_updateTimer invalidate];
_updateTimer = nil;
}
And animate every second, from one second, to the next, like this:
- (void)animatePointer {
NSDate *now = [NSDate date];
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSSecondCalendarUnit fromDate:now];
float angleForSeconds = (float)[components second] / 60.0;
[UIView animateWithDuration:1.0 animations:^(void){
_pointerGlow.layer.transform = CATransform3DMakeRotation((M_PI * 2) * angleForSeconds, 0, 0, 1);
}];
}
This does work, but it's not smooth. It stops for a fraction of a second, every second, like a tipical wall clock would. Nice, but not what I'm going for.
Is there any way I could make this animation silky smooth?
You could try it with a CADisplayLink which is tied to the display refresh rate of 60/second. The code looks like this (note that I didn't add any logic to stop the display link, but I put in the method that you would call if you wanted to):
#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>
#interface ViewController ()
#property (nonatomic, strong) CADisplayLink *displayLink;
#property (nonatomic) CFTimeInterval firstTimestamp;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self startDisplayLink];
}
- (void)startDisplayLink {
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(handleDisplayLink:)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)stopDisplayLink {
[self.displayLink invalidate];
self.displayLink = nil;
}
- (void)handleDisplayLink:(CADisplayLink *)displayLink {
if (!self.firstTimestamp) self.firstTimestamp = displayLink.timestamp;
NSTimeInterval elapsed = (displayLink.timestamp - self.firstTimestamp);
self.arrow.layer.transform = CATransform3DMakeRotation((M_PI * 2) * elapsed/60, 0, 0, 1);
}

Resources