What I want is to animate my UILabel's text between 3 values repeatedly. The text I'd like to set is 'downloading.', 'downloading..', 'downloading...', and then, repeat. With this animation, I want to let my user know that the downloading is being done and the app is not stacked. I've been searching with google for a while and did not find a solution.
Any one can give me some reference about this? Thanks in advance.
Use the NStimer for changing the text
in .h file
#interface ViewController : UIViewController
{
NSTimer * timer;
UILabel * downloadingLbl;
}
and in .m file
- (void)viewDidLoad
{
[super viewDidLoad];
downloadingLbl.text = #"Downloading.";
if (!timer) {
timer = [NSTimer timerWithTimeInterval:0.5 target:self selector:#selector(onTick:) userInfo:nil repeats:YES];
}
}
-(void)onTick:(NSTimer*)timer
{
NSLog(#"Tick...");
if ([downloadingLbl.text isEqualToString:#"Downloading."]) {
downloadingLbl.text = #"Downloading..";
} else if ([downloadingLbl.text isEqualToString:#"Downloading.."]) {
downloadingLbl.text = #"Downloading...";
} else if ([downloadingLbl.text isEqualToString:#"Downloading..."]) {
downloadingLbl.text = #"Downloading.";
}
}
And when your download complete that make timer invalidate.
[timer invalidate];
for that you have to schedule the timer like this:
int count = 1;
NSTimer *myTimer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(updateLabel)
userInfo:nil
repeats:YES];
Now below method will get called in every (in seconds) periods
- (void) updateLabel {
if(count == 1)
{
label.text = #"Downloading."
count = 2;
}
else if(count == 2)
{
label.text = #"Downloading.."
count = 3;
}
else if(count == 3)
{
label.text = #"Downloading..."
count = 1;
}
}
whenever you want to stop Updating do this,in scenario you want to stop downloding :
[timer invalidate];
Updated Johnston 's answer for Swift:
ellipsisTimer = NSTimer.scheduledTimerWithTimeInterval(0.6, target: self, selector: #selector(LinkCheckViewController.updateLabelEllipsis(_:)), userInfo: nil, repeats: true)
func updateLabelEllipsis(timer: NSTimer) {
let messageText: String = self.ThreeDotLabel.text!
let dotCount: Int = (ThreeDotLabel.text?.characters.count)! - messageText.stringByReplacingOccurrencesOfString(".", withString: "").characters.count + 1
self.ThreeDotLabel.text = " "
var addOn: String = "."
if dotCount < 4 {
addOn = "".stringByPaddingToLength(dotCount, withString: ".", startingAtIndex: 0)
}
self.ThreeDotLabel.text = self.ThreeDotLabel.text!.stringByAppendingString(addOn)
}
In viewDidLoad:
self.downloadingLabel.text = #"downloading.";
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(tick:) userInfo:nil repeats:YES];
Then add the method:
- (void) tick:(NSTimer *) timer {
if ([self.downloadingLabel.text isEqual: #"downloading..."])
self.downloadingLabel.text = #"downloading.";
else
self.downloadingLabel.text = [self.downloadingLabel.text stringByAppendingString:#"."];
}
This will do what you asked for. Although you may want to look into classes like UIActivityIndicatorView;
Use this. It may help you..
if (!timer)
{
timer = [NSTimer timerWithTimeInterval:0.5 target:self selector:#selector(updateLabel) userInfo:nil repeats:YES];
}
Here I add shake animation to indicate downloading progress.
Initially the shake values are..
self.shake = 5;
self.direction = 1;
-(void)shake:(UILabel *)theOneYouWannaShake{
[UIView animateWithDuration:0.01 animations:^
{
theOneYouWannaShake.transform = CGAffineTransformMakeTranslation(5*self.directions, 0);
}
completion:^(BOOL finished)
{
if(self.shakes >= 5)
{
theOneYouWannaShake.transform = CGAffineTransformIdentity;
return;
}
self.shakes++;
self.directions = self.directions * -1;
[self shake:theOneYouWannaShake];
}];
}
- (void) updateLabel {
int status = self.count % 3;
if(status == 0)
{
label.text = #"Downloading."
}
else if(status == 1)
{
label.text = #"Downloading.."
}
else
{
label.text = #"Downloading...";
}
self.count += 1 ;
}
After download complete.
[timer invalidate]
self.count = 0;
I just came to this post in 2015 and I wasn't satisfied with the answers here.
Here's my solution. Change the 4 for as many dots as you want. This will do 3 dots (4 - 1). Change the word Posting to whatever status you need.
First add a timer as stated above.
self.ellipsisTimer = [NSTimer scheduledTimerWithTimeInterval:0.6
target:self
selector:#selector(updateLabelEllipsis:)
userInfo:nil
repeats:YES];
In your update method:
- (void) updateLabelEllipsis:(NSTimer *)timer {
NSString *messageText = [[self messageLabel] text];
NSInteger dotCount = messageText.length - [[messageText stringByReplacingOccurrencesOfString:#"." withString:#""] length] + 1;
[[self messageLabel] setText:#"Posting"];
NSString *addOn = #".";
if (dotCount < 4) {
addOn = [#"" stringByPaddingToLength:dotCount withString: #"." startingAtIndex:0];
}
[[self messageLabel] setText:[[[self messageLabel] text] stringByAppendingString:addOn]];
}
It works by counting the current number of dots and adding one more. Once it goes above the limit it goes back to 1 dot.
Change the UILabel text animation of 0.5 seconds duration with adding 3 texts in array and updating all the time until your response succeed.
User NSTimer for updating UILabel text
Related
I want to show user that the value initially is 0 than it increase to 1 than 2 than 3 sequence repeat after some seconds
Worked done by me
I write this code in viewdidload but it print 99 in label directly but i want to show user changing values from 0 to 99.
for(int i=0;i<100;i++){
_totalEffort.text=[NSString stringWithFormat:#"%d",i];
}
I think this will help you:
#interface ViewController (){
int i;
NSTimer *myTimer;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
myTimer = [NSTimer scheduledTimerWithTimeInterval:0.5
target:self
selector:#selector(setData)
userInfo:nil
repeats:YES];
i = 0;
}
-(void)setData{
_totalEffort.text=[NSString stringWithFormat:#"%d",i];
i = i + 1;
if(i == 100){
[myTimer invalidate];
myTimer = nil;
}
}
Based on your requirement you need to use NSTimer for update your label progress
Step 1: Create 2 variable in your #interface class
#interface BUViewController: UIViewController {
NSTimer *timerCount;
int progress;
}
Step 2: Start Timer in your viewDidLoad() with progress value 0.
progress = 0;
timerCount = [NSTimer timerWithTimeInterval:0.5 target:self selector:#selector(updateLabel) userInfo:nil repeats:YES];
Step 3: create method with timer update label text an check progress value in it and stop timer while its reach 100.
-(void)updateLable{
if (progress<100) {
lblProgress.text = [NSString stringWithFormat:#"%d",progress];
progress++;
}else{
[timerCount invalidate];
timerCount = nil;
}
}
Hope this will help you to achieve your expected output.
For this you can use NSTimer you need to update UILabel value in its selector method. You can use this code.
-(void)viewDidLoad{
[super viewDidLoad];
self.time = 0;
_labelTimer.text =#"0";
[self startTimer];
}
- (void)startTimer {
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(timerAction:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
}
- (void)timerAction:(NSTimer *)timer {
self.time++;
if (self.time == 100)
{
[self stopTimer];
}
_labelTimer.text = [NSString stringWithFormat:#"%d",self.time];
}
-(void)stopTimer{
[self.timer invalidate];
self.timer = nil;
}
Here is code for your problem .hope it helps you.
- (void)viewDidLoad
{
[super viewDidLoad];
counter = 0;
t = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(updateLabel) userInfo:nil repeats:YES];
}
-(void)updateLabel
{
for (int i = counter; i<counter+1; i++)
{
_totalEffort.text=[NSString stringWithFormat:#"%d",i];
}
counter++;
if (counter ==101)
{
[t invalidate];
}
}
You are blocking run loop with your cycle. You just need resume it in each iteration.
for(int i=0;i<100;i++){
_totalEffort.text=#(i).stringValue;
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
}
I have a requirment of 15sec timer in my app in the circular progress bar sort of animation which will contain label in the center of seconds remain
Following code gives the labelprogress from 0.0 to 1.0f but I want to map it to 15 seconds countdown with the smooth animation also if there is timer extender than it should get the time added with the smooth animation
ex: Firstly I need to start from 15 seconds and if user clicks on the timeextender powerup and current time is the 10sec then it should be 25 sec and acoordingly the progressbar percentage should work.
So what logic I need to map to get the above requirement done
- (void)progressChange
{
// Labeled progress views
NSArray *labeledProgressViews = #[//self.labeledProgressView,
self.labeledLargeProgressView];
for (DALabeledCircularProgressView *labeledProgressView in labeledProgressViews) {
CGFloat progress = ![self.timer isValid] ? self.stepper.value / 10.0f : labeledProgressView.progress + 0.01f;
[labeledProgressView setProgress:progress animated:YES];
labeledProgressView.progressLabel.text = [NSString stringWithFormat:#"%.2f", labeledProgressView.progress];
}
}
- (void)startAnimation
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.03
target:self
selector:#selector(progressChange)
userInfo:nil
repeats:YES];
self.continuousSwitch.on = YES;
}
- (void)stopAnimation
{
[self.timer invalidate];
self.timer = nil;
self.continuousSwitch.on = NO;
}
- (IBAction)TimeExtender:(id)sender
{
if (labeledProgressView.progress >= 1.0f && [self.timer isValid]) {
[labeledProgressView setProgress:0.f animated:YES];
}
}
I solved it by myself here's the code
- (void)progressChange
{
CGFloat progress ;
DALabeledCircularProgressView *labeledProgressView = self.labeledLargeProgressView;
if(labeledProgressView.progress >=1.0f && [self.timer isValid]){
[self stopAnimation];
seconds = 15.0f;
}
else{
progress=labeledProgressView.progress + 0.06666667f;
[labeledProgressView setProgress:progress animated:YES];
seconds --;
labeledProgressView.progressLabel.text = [NSString stringWithFormat:#"%i", seconds];
}
}
- (void)startAnimation
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(progressChange)
userInfo:nil
repeats:YES];
self.continuousSwitch.on = YES;
}
- (void)viewDidLoad{
[super viewDidLoad];
counterLabel.text = [NSString stringWithFormat:#"Your counter is: %d",seconds];
seconds = 0;
randomTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0/1.0) target:self selector:#selector(randomMainVoid) userInfo:nil repeats:YES];
}
-(void)randomMainVoid{
seconds += 1;
counterLabel.text = [NSString stringWithFormat:#"Your counter is: %d",seconds];
}
-(IBAction)Green:(id)sender{
seconds+=2;
colorLabel.textColor = [UIColor greenColor];
colorLabel.text = #"Your color is: Green";
}
My first method is updating the seconds and displaying it. I have a button, when I click it i want the seconds to go up double. How would I do that?
I'm working on creating a timer, which is in the format of HH:mm, but my issue right now is pausing the timer and resuming it. Right now, when you pause the timer, it continues to count in the background, but the visible portion has stopped. Once you click on the resume button, the timer updates to where it left off, which, pending how long you it had been paused, could be any number above what it should be.
For instance, if the timer counted to 5, you then pause the timer, which now is sitting at 5, once you click resume, the timer may start at 15 since it had been 10 seconds since you paused it. Below is my code, which I have combined from several places to get this working:
- (void) createTimerPage
{
_dateFormat = [NSDate date];
// Add pause button
UIImage *pause = [UIImage imageNamed:#"pause.png"];
_pauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_pauseBtn.frame = CGRectMake(151, 17, 32, 32);
[_pauseBtn addTarget:self action:#selector(pauseTimer) forControlEvents:UIControlEventTouchUpInside];
[_pauseBtn setBackgroundImage:pause forState:UIControlStateNormal];
}
- (void) startTimer
{
// Start timer
NSInteger secondsSinceStart = (NSInteger) [[NSDate date] timeIntervalSinceDate:_dateFormat];
NSInteger seconds = secondsSinceStart % 60;
NSInteger minutes = (secondsSinceStart / 60) % 60;
NSString *result = nil;
result = [NSString stringWithFormat:#"%02d:%02d", minutes, seconds];
_timerText.text = result;
[_timerBtns addSubview:_pauseBtn];
}
- (void) startPressed
{
[_time invalidate];
_time = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(startTimer)
userInfo:nil
repeats:YES];
}
- (void) pauseTimer
{
if (_time) {
// pause timer
[_time invalidate];
[_timerBtns addSubview:_playBtn];
}
}
I suspect the problem is that you are storing the "start time" in the variable called "_dateFormat". That variable only gets set when createTimerPage is called so, of course, when you later attempt to determine the secondsSinceStart in startTimer, it is still computing the time since createTimerPage was called.
Honestly, for what you are trying to do, I would not worry about a start time at all. Instead, I would just use a counter of the number of times the timer method gets called. I would also rename some of your methods to make it clearer what is actually going on. For example, your "startTimer" method isn't actually starting a timer. It's what gets called when your one second timer fires.
Finally, one other issue is that you are constantly adding subviews but, at least with the code posted, never removing them. You could (should) remove the unused subview every time you add a new one. Honestly, though, you would be better off leaving both views as part of your view hierarchy and using the hidden attribute to only show one of them.
Something like this will do what you want:
NSUInteger _timerSeconds;
NSTimer * _timer;
- (void) createTimerPage
{
// Add pause button
UIImage *pause = [UIImage imageNamed:#"pause.png"];
_pauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_pauseBtn.frame = CGRectMake(151, 17, 32, 32);
[_pauseBtn addTarget:self action:#selector(pausePressed) forControlEvents:UIControlEventTouchUpInside];
[_pauseBtn setBackgroundImage:pause forState:UIControlStateNormal];
[_timerBtns addSubview:_pauseBtn];
}
- (void) timerFired
{
_timerSeconds++;
NSInteger seconds = _timerSeconds % 60;
NSInteger minutes = (_timerSeconds / 60) % 60;
NSString * result = [NSString stringWithFormat:#"%02d:%02d", minutes, seconds];
_timerText.text = result;
}
- (void) startPressed
{
// start timer
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(timerFired)
userInfo:nil
repeats:YES];
_playBtn.hidden = YES;
_pauseBtn.hidden = NO;
}
- (void) pausePressed
{
if (_timer) {
// pause timer
[_timer invalidate];
_playBtn.hidden = NO;
_pauseBtn.hidden = YES;
}
}
I was actually able to figure this one out with some more research on the matter. I found a great example that helped me come up with the following:
- (IBAction)startRepeatingTimer:(id)sender
{
// Show feed text while timer is going
_feeding = [[UILabel alloc] initWithFrame:CGRectMake(92, 25, 100, 50)];
_feeding.text = #"FEEDING";
_feeding.textColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:1];
if (_feeding) {
_feeding.hidden = NO;
}
[_timerArea addSubview:_feeding];
// Cancel preexisting timer
[_repeatingTimer invalidate];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(timerTicked:)
userInfo:nil repeats:YES];
_repeatingTimer = timer;
if (_playBtn.hidden == NO) {
_playBtn.hidden = YES;
_pauseBtn.hidden = NO;
}
if (_bWindow.frame.origin.y == 0) {
[UIView animateWithDuration:0.3
animations:^ {
_bWindow.frame = CGRectMake(0, 0, self.view.frame.size.width, 203);
_bWindow.frame = CGRectMake(0, -130, self.view.frame.size.width, 203);
}];
}
[_timerBtns addSubview:_pauseBtn];
}
- (void) timerTicked:(NSTimer *)timer
{
_currentTimeInSeconds++;
_timerText.text = [self targetMethod:_currentTimeInSeconds];
}
- (IBAction)resetTimer:(id)sender
{
_feeding.hidden = YES;
if (_repeatingTimer) {
[_repeatingTimer invalidate];
}
if (_playBtn.hidden == YES) {
_playBtn.hidden = NO;
_pauseBtn.hidden = YES;
}
_currentTimeInSeconds = 0;
_timerText.text = [self targetMethod:_currentTimeInSeconds];
if (_bothBtn.hidden == YES) {
_bothBtn.hidden = NO;
_switchBView.hidden = YES;
}
if (_rightBtn.hidden == YES) {
_rightBtn.hidden = NO;
_switchRView.hidden = YES;
}
if (_leftBtn.hidden == YES) {
_leftBtn.hidden = NO;
_switchLView.hidden = YES;
}
}
- (IBAction)pauseRepeatingTimer:(id)sender
{
[_repeatingTimer invalidate];
if (_playBtn.hidden == YES) {
_playBtn.hidden = NO;
_pauseBtn.hidden = YES;
}
}
- (NSString *) targetMethod:(int)totalSeconds
{
//NSInteger secondsSinceStart = (NSInteger) [[NSDate date] timeIntervalSinceDate:_dateFormat];
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
return [NSString stringWithFormat:#"%02d:%02d", minutes, seconds];
}
I made a stopwatch application recently and it had a few glitches.
If I hit the stop button twice in a row, the entire app would crash.
If I hit the start button twice in a row, the timer would run twice as fast and the stop button would stop working.
How do I fix this problem?
Here is the code in my .h file:
IBOutlet UILabel *time;
IBOutlet UILabel *time1;
IBOutlet UILabel *time2;
NSTimer *myTicker;
NSTimer *myTicker2;
NSTimer *myTicker3;
}
- (IBAction)start;
- (IBAction)stop;
- (IBAction)reset;
- (void)showActivity;
- (void)showActivity1;
- (void)showActivity2;
#end
and here is my code in the .m file:
- (IBAction)start {
myTicker = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(showActivity) userInfo:nil repeats:YES];
myTicker2 = [NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:#selector(showActivity1) userInfo:nil repeats:YES];
myTicker3 = [NSTimer scheduledTimerWithTimeInterval:60 target:self selector:#selector(showActivity2) userInfo:nil repeats:YES];
}
- (IBAction)stop {
[myTicker invalidate];
[myTicker2 invalidate];
[myTicker3 invalidate];
}
- (IBAction)reset {
time.text = #"00";
time1.text = #"00";
time2.text = #"00";
}
- (void)showActivity {
int currentTime = [time.text intValue];
int newTime = currentTime + 1;
if (newTime == 60) {
newTime = 0;
}
time.text = [NSString stringWithFormat:#"%d", newTime];
}
- (void)showActivity1 {
int currentTime1 = [time1.text intValue];
int newTime1 = currentTime1 + 1;
if (newTime1 == 10) {
newTime1 = 0;
}
time1.text = [NSString stringWithFormat:#"%d", newTime1];
}
- (void)showActivity2 {
int currentTime2 = [time2.text intValue];
int newTime2 = currentTime2 + 1;
time2.text = [NSString stringWithFormat:#"%d", newTime2];
}
Set the stop button's userInterActionEnabled property to NO and the start button's to YES when the -stop method is fired. Then switch and set the stop button's userInterActionEnabled to YES and the start button's to NO when -start is fired.
You should create a private BOOL variable "isRunning", which is checked when clicked on Stop or Start like:
- (IBAction)stop {
if(!isRunning) return;
[myTicker invalidate];
[myTicker2 invalidate];
[myTicker3 invalidate];
self.isRunning = NO;
}
etc. Also ignoring user interactions is general a good idea (like CodaFi suggested), but only fights the symptoms ;-) You really should do both checks.